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