r109: reorganized header files
[ctsim.git] / libctgraphics / sgp.cpp
1 /*****************************************************************************
2 ** FILE IDENTIFICATION
3 **
4 **      Name:       sgp.c               Simple Graphics Package
5 **      Programmer: Kevin Rosenberg
6 **
7 **  This is part of the CTSim program
8 **  Copyright (C) 1983-2000 Kevin Rosenberg
9 **
10 **  $Id: sgp.cpp,v 1.2 2000/06/19 19:04:05 kevin Exp $
11 **
12 **  This program is free software; you can redistribute it and/or modify
13 **  it under the terms of the GNU General Public License (version 2) as
14 **  published by the Free Software Foundation.
15 **
16 **  This program is distributed in the hope that it will be useful,
17 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
18 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 **  GNU General Public License for more details.
20 **
21 **  You should have received a copy of the GNU General Public License
22 **  along with this program; if not, write to the Free Software
23 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24 ******************************************************************************/
25
26 #include <stdio.h>
27 #include <math.h>
28 #include "ctsupport.h"
29 #include "sgp.h"
30
31
32 static SGP_ID _sgp2_cwin = NULL;
33
34 extern CHARSPEC cspec;
35
36
37 /* NAME
38  *   sgp2_init                          Initialize 2 graphics system
39  *
40  * SYNOPSIS
41  *   sgp2_init()
42  */
43
44 SGP_ID
45 sgp2_init (int xsize, int ysize, const char *win_title )
46 {
47     SGP_ID gid;
48
49     gid = new SGP_WINDOW;
50     _sgp2_cwin = gid;
51  
52     if (xsize <= 0)
53         xsize = 640;
54     if (ysize <= 0)
55         ysize = 480;
56
57     gid->pw_xsize = xsize;
58     gid->pw_ysize = ysize;
59     strncpy(gid->title, win_title, sizeof(gid->title));
60
61     gid->recalc_mc_to_ndc = TRUE;
62     gid->recalc_ndc_to_mc = TRUE;
63     ident_gmtx_2 (gid->wc_to_ndc_x);
64     ident_gmtx_2 (gid->mc_to_ndc_x);
65     ident_gmtx_2 (gid->ndc_to_mc_x);
66     ident_gmtx_2 (gid->ctm_2_x);
67
68     sgp2_window (0., 0., 1., 1.);
69     sgp2_viewport (0., 0., 1., 1.);
70     ctm_clr_2 ();
71     sgp2_move_abs (0., 0.);
72
73 #if HAVE_G2_H
74     gid->g2_id = g2_open_X11X (gid->pw_xsize, gid->pw_ysize, 10, 10, gid->title, gid->title, NULL, -1, -1);
75 #endif
76
77     _sgp2_init_dev (_sgp2_cwin);
78     
79     return (gid);
80 }
81
82
83 void
84 sgp2_close (SGP_ID gid)
85 {
86 #if HAVE_G2_H    
87     g2_close (gid->g2_id);
88 #endif
89     if (gid == _sgp2_cwin)
90         _sgp2_cwin = NULL;
91
92     delete gid;
93 }
94
95 void
96 sgp2_set_active_win (SGP_ID gid)
97 {
98     _sgp2_cwin = gid;
99 }
100
101 SGP_ID
102 sgp2_get_active_win (void)
103 {
104     return (_sgp2_cwin);
105 }
106
107
108 /* NAME
109  *      sgp2_clear          Clear window
110  */
111
112 void 
113 sgp2_clear ()
114 {
115 #if HAVE_G2
116     if (_sgp_cwin != NULL)
117         g2_clear (gid->g2_id);
118 #endif
119 }
120
121 /* NAME
122  *      sgp2_window             Set window in world coordinates
123  */
124
125 void
126 sgp2_window (double xmin, double ymin, double xmax, double ymax)
127 {
128     if (_sgp2_cwin == NULL)
129        return;
130
131     if (xmin >= xmax || ymin >= ymax) {
132         sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_window]");
133         return;
134     }
135
136     _sgp2_cwin->xw_min = xmin;
137     _sgp2_cwin->yw_min = ymin;
138     _sgp2_cwin->xw_max = xmax;
139     _sgp2_cwin->yw_max = ymax;
140     calc_wc_to_ndc();
141 }
142
143
144 /* NAME
145  *      sgp2_viewport                   Set viewport in NDC
146  */
147
148 void
149 sgp2_viewport (double xmin, double ymin, double xmax, double ymax)
150 {
151     if (_sgp2_cwin == NULL)
152        return;
153
154     if (xmin >= xmax || ymin >= ymax) {
155         sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_viewport]");
156         return;
157     }
158     
159     _sgp2_cwin->xv_min = xmin;
160     _sgp2_cwin->yv_min = ymin;
161     _sgp2_cwin->xv_max = xmax;
162     _sgp2_cwin->yv_max = ymax;
163     calc_wc_to_ndc();
164     
165     _sgp2_cwin->view[0] = xmin;                 /* Array for clip_rect() */
166     _sgp2_cwin->view[1] = ymin;
167     _sgp2_cwin->view[2] = xmax;
168     _sgp2_cwin->view[3] = ymax;
169 }
170
171
172 /* NAME
173  *      sgp2_frame_vpt          draw box around viewport
174  */
175
176 void
177 sgp2_frame_vpt (void)
178 {
179     if (_sgp2_cwin == NULL)
180         return;
181
182     _sgp2_stylus (_sgp2_cwin, _sgp2_cwin->xv_min, _sgp2_cwin->yv_min, 0);
183     _sgp2_stylus (_sgp2_cwin, _sgp2_cwin->xv_max, _sgp2_cwin->yv_min, 1);
184     _sgp2_stylus (_sgp2_cwin, _sgp2_cwin->xv_max, _sgp2_cwin->yv_max, 1);
185     _sgp2_stylus (_sgp2_cwin, _sgp2_cwin->xv_min, _sgp2_cwin->yv_max, 1);
186     _sgp2_stylus (_sgp2_cwin, _sgp2_cwin->xv_min, _sgp2_cwin->yv_min, 1);
187 }
188
189
190 /* NAME
191  *      calc_wc_to_ndc                  Calculate transform matrix
192  */
193
194 void
195 calc_wc_to_ndc (void)
196 {
197     double sx, sy;
198     
199     if (_sgp2_cwin == NULL)
200         return;
201
202     sx = (_sgp2_cwin->xv_max - _sgp2_cwin->xv_min) / (_sgp2_cwin->xw_max - _sgp2_cwin->xw_min);
203     sy = (_sgp2_cwin->yv_max - _sgp2_cwin->yv_min) / (_sgp2_cwin->yw_max - _sgp2_cwin->yw_min);
204     
205     ident_gmtx_2 (_sgp2_cwin->wc_to_ndc_x);
206     _sgp2_cwin->wc_to_ndc_x[0][0] = sx;
207     _sgp2_cwin->wc_to_ndc_x[2][0] = _sgp2_cwin->xv_min - sx * _sgp2_cwin->xw_min;
208     _sgp2_cwin->wc_to_ndc_x[1][1] = sy;
209     _sgp2_cwin->wc_to_ndc_x[2][1] = _sgp2_cwin->yv_min - sy * _sgp2_cwin->yw_min;
210     
211     _sgp2_cwin->recalc_mc_to_ndc = TRUE;
212     _sgp2_cwin->recalc_ndc_to_mc = TRUE;
213 }
214
215
216 void 
217 calc_ndc_to_mc (void)
218 {
219     if (_sgp2_cwin == NULL)
220         return;
221
222     if (_sgp2_cwin->recalc_mc_to_ndc) {
223         mult_gmtx_2 (_sgp2_cwin->ctm_2_x, _sgp2_cwin->wc_to_ndc_x, _sgp2_cwin->mc_to_ndc_x);
224         _sgp2_cwin->recalc_mc_to_ndc = FALSE;
225     }
226     
227     invert_gmtx_2 (_sgp2_cwin->mc_to_ndc_x, _sgp2_cwin->ndc_to_mc_x);
228     _sgp2_cwin->recalc_ndc_to_mc = FALSE;
229 }
230
231
232 /* NAME
233  *      wc_to_ndc                       Map from world coordinates to NDC
234  */
235
236 void 
237 wc_to_ndc (double xw, double yw, double *xn, double *yn)
238 {
239     if (_sgp2_cwin == NULL)
240         return;
241
242     if (_sgp2_cwin->recalc_mc_to_ndc) {
243         mult_gmtx_2 (_sgp2_cwin->ctm_2_x, _sgp2_cwin->wc_to_ndc_x, _sgp2_cwin->mc_to_ndc_x);
244         _sgp2_cwin->recalc_mc_to_ndc = FALSE;
245     }
246
247     *xn = xw * _sgp2_cwin->mc_to_ndc_x[0][0] + yw * _sgp2_cwin->mc_to_ndc_x[1][0] + _sgp2_cwin->mc_to_ndc_x[2][0];
248     *yn = xw * _sgp2_cwin->mc_to_ndc_x[0][1] + yw * _sgp2_cwin->mc_to_ndc_x[1][1] + _sgp2_cwin->mc_to_ndc_x[2][1];
249 }
250
251
252 /*==============================================================*/
253 /* map from normalized device coords. to world coordinates      */
254 /*==============================================================*/
255 void
256 ndc_to_wc (double xn, double yn, double *xw, double *yw)
257 {
258     if (_sgp2_cwin == NULL)
259         return;
260
261     if (_sgp2_cwin->recalc_ndc_to_mc) {
262         calc_ndc_to_mc();
263         _sgp2_cwin->recalc_ndc_to_mc = FALSE;
264     }
265
266     *xw = xn * _sgp2_cwin->ndc_to_mc_x[0][0] + yn * _sgp2_cwin->ndc_to_mc_x[1][0] + _sgp2_cwin->ndc_to_mc_x[2][0];
267     *yw = xn * _sgp2_cwin->ndc_to_mc_x[0][1] + yn * _sgp2_cwin->ndc_to_mc_x[1][1] + _sgp2_cwin->ndc_to_mc_x[2][1];
268 }
269
270
271 /*==============================================================*/
272 /* set the color                                                */
273 /*==============================================================*/
274 void 
275 sgp2_color (int icol)
276 {
277     setcolor(icol);
278 }
279
280 /*==============================================================*/
281 /* set line style.  Pass 16 bit repeating pattern               */
282 /*==============================================================*/
283 void 
284 sgp2_line_style (int style)
285 {
286     setlinestyle(style);
287 }
288
289 /*==============================================================*/
290 /* absolute draw to                                             */
291 /*==============================================================*/
292 void 
293 sgp2_line_abs (double x, double y)
294 {
295     double x1, y1, x2, y2;
296
297     if (_sgp2_cwin == NULL)
298         return;
299
300     wc_to_ndc (_sgp2_cwin->curx, _sgp2_cwin->cury, &x1, &y1);
301     wc_to_ndc (x, y, &x2, &y2);
302
303     if (clip_rect (x1, y1, x2, y2, _sgp2_cwin->view) == TRUE) { /* clip to viewport */
304         _sgp2_stylus (_sgp2_cwin, x1, y1, 0);           /* move to first point */
305         _sgp2_stylus (_sgp2_cwin, x2, y2, 1);           /* draw to second point */
306     }
307
308     _sgp2_cwin->curx = x;
309     _sgp2_cwin->cury = y;
310 }
311
312 /*==============================================================*/
313 /* absolute move to                                             */
314 /*==============================================================*/
315 void 
316 sgp2_move_abs (double x, double y)
317 {
318     if (_sgp2_cwin == NULL)
319         return;
320
321     _sgp2_cwin->curx = x;
322     _sgp2_cwin->cury = y;                       /* moves are not clipped */
323 }
324
325 /*==============================================================*/
326 /* vector draw                                                  */
327 /*==============================================================*/
328 void 
329 sgp2_line_rel (double x, double y)
330 {
331     if (_sgp2_cwin != NULL)
332         sgp2_line_abs (x + _sgp2_cwin->curx, y + _sgp2_cwin->cury);
333 }
334
335 /*==============================================================*/
336 /* vector move                                                  */
337 /*==============================================================*/
338 void 
339 sgp2_move_rel (double x, double y)
340 {
341     if (_sgp2_cwin != NULL)
342         sgp2_move_abs (x + _sgp2_cwin->curx, y + _sgp2_cwin->cury);
343 }
344
345 /*==============================================================*/
346 /* draw text                                                    */
347 /*==============================================================*/
348 void 
349 sgp2_draw_text (char *message)
350 {
351     double sx,sy;
352     if (_sgp2_cwin == NULL)
353         return;
354
355     wc_to_ndc (_sgp2_cwin->curx, _sgp2_cwin->cury, &sx, &sy);
356     _sgp2_stylus (_sgp2_cwin, sx, sy, 0);       /* move to location */
357     _sgp2_dev_text (_sgp2_cwin, message);
358 }
359
360 void
361 charsize (double wid, double height)
362 {
363     _sgp2_set_text (_sgp2_cwin, wid, height, cspec.textangle, cspec.font);
364 }
365
366 void
367 textangle (double angle)
368 {
369     _sgp2_set_text (_sgp2_cwin, cspec.width, cspec.height, angle, cspec.font);
370 }
371
372 void 
373 sgp2_polyline_abs (double x[], double y[], int n)
374 {
375     double x1, y1, x2, y2;
376     int i;
377     double xt, yt;
378
379     if (_sgp2_cwin == NULL || n < 2)
380         return;
381
382     wc_to_ndc (x[0], y[0], &x1, &y1);
383     wc_to_ndc (x[1], y[1], &x2, &y2);
384
385     xt = x2;            /* don't pass (x2,y2) to clip, we need them */
386     yt = y2;            /* as the beginning point of the next line */
387
388     if (clip_rect (x1, y1, xt, yt, _sgp2_cwin->view) == TRUE) {
389         _sgp2_stylus (_sgp2_cwin, x1, y1, 0);
390         _sgp2_stylus (_sgp2_cwin, xt, yt, 1);
391     }
392
393     for (i = 2; i < n; i++) {
394         x1 = x2;                        /* NDC endpoint of last line */
395         y1 = y2;
396         wc_to_ndc (x[i], y[i], &x2, &y2);
397         xt = x2;
398         yt = y2;
399         if (clip_rect (x1, y1, xt, yt, _sgp2_cwin->view) == TRUE) {
400             _sgp2_stylus (_sgp2_cwin, x1, y1, 0);
401             _sgp2_stylus (_sgp2_cwin, xt, yt, 1);
402         }
403     }
404 }
405
406
407 void 
408 sgp2_mark_abs (double x, double y)
409 {
410     double xndc, yndc;
411
412     if (_sgp2_cwin == NULL)
413         return;
414
415     wc_to_ndc (x, y, &xndc, &yndc);
416     markndc (_sgp2_cwin, xndc, yndc);
417     _sgp2_cwin->curx = x;
418     _sgp2_cwin->cury = y;
419 }
420
421
422 void 
423 sgp2_mark_rel (double x, double y)
424 {
425     sgp2_mark_abs (x + _sgp2_cwin->curx, y + _sgp2_cwin->cury);
426 }
427
428
429 void 
430 sgp2_point_abs (double x, double y)
431 {
432     double xndc, yndc;
433
434     if (_sgp2_cwin == NULL)
435         return;;
436
437     wc_to_ndc (x, y, &xndc, &yndc);
438     pntndc (_sgp2_cwin, xndc, yndc);
439     _sgp2_cwin->curx = x;
440     _sgp2_cwin->cury = y;
441 }
442
443
444 void 
445 sgp2_point_rel (double x, double y)
446 {
447     sgp2_point_abs (x + _sgp2_cwin->curx, y + _sgp2_cwin->cury);
448 }
449
450
451 /*----------------------------------------------------------------------*/
452 /*                   Current Transformation Matrix Routine              */
453 /*----------------------------------------------------------------------*/
454
455
456 /* NAME
457  *      ctm_clr_2                       Clear current transformation matrix
458  *
459  * SYNOPSIS
460  *      ctm_clr_2()
461  */
462
463 void 
464 ctm_clr_2 (void)
465 {
466     GRFMTX_2D m;
467
468     ident_gmtx_2 (m);
469     ctm_set_2 (m);
470 }
471
472
473 /* NAME
474  *      ctm_get_2                       Get ctm
475  *
476  * SYNOPSIS
477  *      ctm_get_2 (m)
478  * OUT  GRFMTX_2D m                     Copy of ctm
479  */
480
481 void 
482 ctm_get_2 (GRFMTX_2D m)
483 {
484     int x, y;
485
486     if (_sgp2_cwin == NULL)
487         return;
488
489     for (x = 0; x < 3; x++)
490         for (y = 0; y < 3; y++)
491             m[x][y] = _sgp2_cwin->ctm_2_x[x][y];
492 }
493
494
495 /* NAME
496  *      ctm_set_2                       Set ctm to a matrix
497  *
498  * SYNOPSIS
499  *      ctm_get_ctm_2 (m)
500  * IN   GRFMTX m                        New ctm
501  */
502
503 void 
504 ctm_set_2 (GRFMTX_2D m)
505 {
506     int x, y;
507     if (_sgp2_cwin == NULL)
508         return;
509
510     for (x = 0; x < 3; x++)
511         for (y = 0; y < 3; y++)
512             _sgp2_cwin->ctm_2_x[x][y] = m[x][y];
513
514     _sgp2_cwin->recalc_ndc_to_mc = TRUE;
515     _sgp2_cwin->recalc_mc_to_ndc = TRUE;
516 }
517
518
519 void 
520 ctm_pre_mult_2 (GRFMTX_2D m)
521 {
522     GRFMTX_2D new_ctm;
523
524     mult_gmtx_2 (m, _sgp2_cwin->ctm_2_x, new_ctm);
525     ctm_set_2 (new_ctm);
526 }
527
528
529 void 
530 ctm_post_mult_2 (GRFMTX_2D m)
531 {
532     GRFMTX_2D new_ctm;
533
534     mult_gmtx_2 (_sgp2_cwin->ctm_2_x, m, new_ctm);
535     ctm_set_2 (new_ctm);
536 }