1 /*
2 * $Id: engine.c,v 1.1 2005-09-18 22:04:19 dhmunro Exp $
3 * Implement common properties of all GIST engines
4 */
5 /* Copyright (c) 2005, The Regents of the University of California.
6 * All rights reserved.
7 * This file is part of yorick (http://yorick.sourceforge.net).
8 * Read the accompanying LICENSE file for details.
9 */
10
11 #include "gist.h"
12 #include "engine.h"
13 #include "draw.h"
14 #include "pstdlib.h"
15
16 Engine *gistEngines= 0;
17 Engine *gistActive= 0;
18 Engine *gistPreempt= 0;
19
20 #include <string.h>
21
22 static void DefaultClearArea(Engine *engine, GpBox *box);
23 static void MoreScratch(long np, long ns);
24
25 /* ------------------------------------------------------------------------ */
26
27 /* ARGSUSED */
DefaultClearArea(Engine * engine,GpBox * box)28 static void DefaultClearArea(Engine *engine, GpBox *box)
29 {
30 /* Default ClearArea triggers complete redraw */
31 engine->Clear(engine, CONDITIONALLY);
32 engine->lastDrawn= -1;
33 engine->systemsSeen[0]= engine->systemsSeen[1]= 0;
34 engine->damaged= engine->inhibit= 0;
35 }
36
GpNewEngine(long size,char * name,g_callbacks * on,GpTransform * transform,int landscape,void (* Kill)(Engine *),int (* Clear)(Engine *,int),int (* Flush)(Engine *),void (* ChangeMap)(Engine *),int (* ChangePalette)(Engine *),int (* DrawLines)(Engine *,long,const GpReal *,const GpReal *,int,int),int (* DrawMarkers)(Engine *,long,const GpReal *,const GpReal *),int (* DrwText)(Engine * e,GpReal,GpReal,const char *),int (* DrawFill)(Engine *,long,const GpReal *,const GpReal *),int (* DrawCells)(Engine *,GpReal,GpReal,GpReal,GpReal,long,long,long,const GpColor *),int (* DrawDisjoint)(Engine *,long,const GpReal *,const GpReal *,const GpReal *,const GpReal *))37 Engine *GpNewEngine(long size, char *name, g_callbacks *on,
38 GpTransform *transform, int landscape,
39 void (*Kill)(Engine*), int (*Clear)(Engine*,int), int (*Flush)(Engine*),
40 void (*ChangeMap)(Engine*), int (*ChangePalette)(Engine*),
41 int (*DrawLines)(Engine*,long,const GpReal*,const GpReal*,int,int),
42 int (*DrawMarkers)(Engine*,long,const GpReal*,const GpReal *),
43 int (*DrwText)(Engine*e,GpReal,GpReal,const char*),
44 int (*DrawFill)(Engine*,long,const GpReal*,const GpReal*),
45 int (*DrawCells)(Engine*,GpReal,GpReal,GpReal,GpReal,
46 long,long,long,const GpColor*),
47 int (*DrawDisjoint)(Engine*,long,const GpReal*,const GpReal*,
48 const GpReal*,const GpReal*))
49 {
50 long lname= name? strlen(name) : 0;
51 Engine *engine;
52 /* For Electric Fence package and maybe others, it is nice to ensure
53 that size of block allocated for Engine is a multiple of the size
54 of the most restrictively aligned object which can be in any
55 Engine; assume this is a double. */
56 lname= (lname/sizeof(double) + 1)*sizeof(double); /* >= lname+1 */
57 engine= (Engine *)p_malloc(size+lname);
58 if (!engine) return 0;
59
60 /* Fill in Engine properties, link into gistEngines list */
61 engine->next= gistEngines;
62 gistEngines= engine;
63 engine->nextActive= 0;
64 engine->name= (char *)engine + size;
65 strcpy(name? engine->name : "", name);
66 engine->on = on;
67 engine->active= 0;
68 engine->marked= 0;
69
70 engine->transform= *transform;
71 engine->landscape= landscape? 1 : 0;
72 GpDeviceMap(engine);
73 /* (a proper map will be installed when the engine is activated) */
74 engine->map.x.scale= engine->map.y.scale= 1.0;
75 engine->map.x.offset= engine->map.y.offset= 0.0;
76
77 /* No pseudocolor map initially */
78 engine->colorChange= 0;
79 engine->colorMode= 0;
80 engine->nColors= 0;
81 engine->palette= 0;
82
83 /* No associated drawing initially */
84 engine->drawing= 0;
85 engine->lastDrawn= -1;
86 engine->systemsSeen[0]= engine->systemsSeen[1]= 0;
87 engine->inhibit= 0;
88 engine->damaged= 0; /* causes Clear if no ClearArea virtual function */
89 engine->damage.xmin= engine->damage.xmax=
90 engine->damage.ymin= engine->damage.ymax= 0.0;
91
92 /* Fill in virtual function table */
93 engine->Kill= Kill;
94 engine->Clear= Clear;
95 engine->Flush= Flush;
96 engine->ChangeMap= ChangeMap;
97 engine->ChangePalette= ChangePalette;
98 engine->DrawLines= DrawLines;
99 engine->DrawMarkers= DrawMarkers;
100 engine->DrwText= DrwText;
101 engine->DrawFill= DrawFill;
102 engine->DrawCells= DrawCells;
103 engine->DrawDisjoint= DrawDisjoint;
104 engine->ClearArea= &DefaultClearArea; /* damage causes complete redraw */
105
106 return engine;
107 }
108
GpDelEngine(Engine * engine)109 void GpDelEngine(Engine *engine)
110 {
111 Engine *eng= gistEngines;
112 if (!engine) return;
113
114 /* Unlink from gistEngines list */
115 if (engine->active) GpDeactivate(engine);
116 if (eng==engine) gistEngines= engine->next;
117 else {
118 /* Because of recursive deletes necessary to deal with X window
119 deletions (see xbasic.c:ShutDown, hlevel.c:ShutDownDev), if
120 the engine has already been removed from the list, it means that
121 this routine is being called for the second time for this engine,
122 and p_free must NOT be called. Fix this someday. */
123 while (eng && eng->next!=engine) eng= eng->next;
124 if (!eng) return;
125 eng->next= engine->next;
126 }
127
128 p_free(engine);
129 }
130
131 /* ------------------------------------------------------------------------ */
132
GpKillEngine(Engine * engine)133 void GpKillEngine(Engine *engine)
134 {
135 if (engine) engine->Kill(engine);
136 }
137
GpActivate(Engine * engine)138 int GpActivate(Engine *engine)
139 {
140 if (!engine) return 1;
141 if (!engine->active) {
142 engine->active= 1;
143 engine->nextActive= gistActive;
144 gistActive= engine;
145 engine->ChangeMap(engine);
146 }
147 return 0;
148 }
149
GpDeactivate(Engine * engine)150 int GpDeactivate(Engine *engine)
151 {
152 if (!engine) return 1;
153 if (engine->active) {
154 Engine *active= gistActive;
155 engine->active= 0;
156 if (active==engine) gistActive= engine->nextActive;
157 else {
158 while (active->nextActive!=engine) active= active->nextActive;
159 active->nextActive= engine->nextActive;
160 }
161 }
162 return 0;
163 }
164
GpPreempt(Engine * engine)165 int GpPreempt(Engine *engine)
166 {
167 gistPreempt= engine;
168 if (engine && !engine->active) engine->ChangeMap(engine);
169 return 0;
170 }
171
GpActive(Engine * engine)172 int GpActive(Engine *engine)
173 {
174 if (!engine) return 0;
175 return engine==gistPreempt? 1 : engine->active;
176 }
177
GpClear(Engine * engine,int flag)178 int GpClear(Engine *engine, int flag)
179 {
180 int value= 0;
181 if (!engine) {
182 for (engine=GpNextActive(0) ; engine ; engine=GpNextActive(engine)) {
183 engine->damaged= engine->inhibit= 0;
184 engine->lastDrawn= -1;
185 engine->systemsSeen[0]= engine->systemsSeen[1]= 0;
186 value|= engine->Clear(engine, flag);
187 }
188 } else {
189 engine->damaged= engine->inhibit= 0;
190 engine->lastDrawn= -1;
191 engine->systemsSeen[0]= engine->systemsSeen[1]= 0;
192 value= engine->Clear(engine, flag);
193 }
194 return value;
195 }
196
GpFlush(Engine * engine)197 int GpFlush(Engine *engine)
198 {
199 if (!engine) {
200 int value= 0;
201 for (engine=GpNextActive(0) ; engine ; engine=GpNextActive(engine))
202 value|= engine->Flush(engine);
203 return value;
204 }
205 return engine->Flush(engine);
206 }
207
GpNextEngine(Engine * engine)208 Engine *GpNextEngine(Engine *engine)
209 {
210 return engine? engine->next : gistEngines;
211 }
212
GpNextActive(Engine * engine)213 Engine *GpNextActive(Engine *engine)
214 {
215 if (gistPreempt) return engine? 0 : gistPreempt;
216 else return engine? engine->nextActive : gistActive;
217 }
218
219 /* ------------------------------------------------------------------------ */
220
GpSetTrans(const GpTransform * trans)221 int GpSetTrans(const GpTransform *trans)
222 {
223 Engine *engine;
224
225 if (trans!=&gistT) gistT= *trans;
226
227 for (engine=GpNextActive(0) ; engine ; engine=GpNextActive(engine))
228 engine->ChangeMap(engine);
229
230 return 0;
231 }
232
GpLandscape(Engine * engine,int landscape)233 int GpLandscape(Engine *engine, int landscape)
234 {
235 if (!engine) {
236 for (engine=GpNextActive(0) ; engine ; engine=GpNextActive(engine))
237 engine->landscape= landscape;
238 } else {
239 engine->landscape= landscape;
240 }
241 return 0;
242 }
243
GpSetMap(const GpBox * src,const GpBox * dst,GpXYMap * map)244 void GpSetMap(const GpBox *src, const GpBox *dst, GpXYMap *map)
245 {
246 map->x.scale= (dst->xmax-dst->xmin)/(src->xmax-src->xmin);
247 map->x.offset= dst->xmin - map->x.scale*src->xmin;
248 map->y.scale= (dst->ymax-dst->ymin)/(src->ymax-src->ymin);
249 map->y.offset= dst->ymin - map->y.scale*src->ymin;
250 }
251
GpDeviceMap(Engine * engine)252 void GpDeviceMap(Engine *engine)
253 {
254 GpSetMap(&engine->transform.viewport, &engine->transform.window,
255 &engine->devMap);
256 }
257
GpComposeMap(Engine * engine)258 void GpComposeMap(Engine *engine)
259 {
260 GpMap *devx= &engine->devMap.x;
261 GpMap *devy= &engine->devMap.y;
262 GpMap *mapx= &engine->map.x;
263 GpMap *mapy= &engine->map.y;
264 mapx->scale=
265 devx->scale*(gistT.viewport.xmax-gistT.viewport.xmin)/
266 (gistT.window.xmax-gistT.window.xmin);
267 mapx->offset= devx->offset + devx->scale*gistT.viewport.xmin -
268 mapx->scale*gistT.window.xmin;
269 mapy->scale=
270 devy->scale*(gistT.viewport.ymax-gistT.viewport.ymin)/
271 (gistT.window.ymax-gistT.window.ymin);
272 mapy->offset= devy->offset + devy->scale*gistT.viewport.ymin -
273 mapy->scale*gistT.window.ymin;
274 }
275
276 /* ------------------------------------------------------------------------ */
277
278 /* Scratch space used by GpIntPoints and GpIntSegs */
279 static void *scratch= 0;
280 static long scratchPoints= 0, scratchSegs= 0;
281
MoreScratch(long np,long ns)282 static void MoreScratch(long np, long ns)
283 {
284 if (scratch) p_free(scratch);
285 if (np) {
286 np+= 64;
287 scratch= (void *)p_malloc(sizeof(GpPoint)*np);
288 scratchPoints= np;
289 scratchSegs= (sizeof(GpPoint)*np)/sizeof(GpSegment);
290 } else {
291 ns+= 32;
292 scratch= (void *)p_malloc(sizeof(GpSegment)*ns);
293 scratchSegs= ns;
294 scratchPoints= (sizeof(GpSegment)*ns)/sizeof(GpPoint);
295 }
296 }
297
GpIntPoints(const GpXYMap * map,long maxPoints,long n,const GpReal * x,const GpReal * y,GpPoint ** result)298 long GpIntPoints(const GpXYMap *map, long maxPoints, long n,
299 const GpReal *x, const GpReal *y, GpPoint **result)
300 {
301 GpReal scalx= map->x.scale, offx= map->x.offset;
302 GpReal scaly= map->y.scale, offy= map->y.offset;
303 long i, np= maxPoints<n? maxPoints : n;
304 GpPoint *point;
305
306 if (np+1>scratchPoints) MoreScratch(np+1, 0); /* allow for closure pt */
307 *result= point= scratch;
308
309 for (i=0 ; i<np ; i++) {
310 point[i].x= (short)(scalx*x[i]+offx);
311 point[i].y= (short)(scaly*y[i]+offy);
312 }
313
314 return np;
315 }
316
GpIntSegs(const GpXYMap * map,long maxSegs,long n,const GpReal * x1,const GpReal * y1,const GpReal * x2,const GpReal * y2,GpSegment ** result)317 long GpIntSegs(const GpXYMap *map, long maxSegs, long n,
318 const GpReal *x1, const GpReal *y1,
319 const GpReal *x2, const GpReal *y2, GpSegment **result)
320 {
321 GpReal scalx= map->x.scale, offx= map->x.offset;
322 GpReal scaly= map->y.scale, offy= map->y.offset;
323 long i, ns= maxSegs<n? maxSegs : n;
324 GpSegment *seg;
325
326 if (ns>scratchSegs) MoreScratch(0, ns);
327 *result= seg= scratch;
328
329 for (i=0 ; i<ns ; i++) {
330 seg[i].x1= (short)(scalx*x1[i]+offx);
331 seg[i].y1= (short)(scaly*y1[i]+offy);
332 seg[i].x2= (short)(scalx*x2[i]+offx);
333 seg[i].y2= (short)(scaly*y2[i]+offy);
334 }
335
336 return ns;
337 }
338
339 /* ------------------------------------------------------------------------ */
340
GpPutGray(int nColors,GpColorCell * palette)341 void GpPutGray(int nColors, GpColorCell *palette)
342 {
343 /*
344 while (nColors--) {
345 palette->gray=
346 ((int)palette->red+(int)palette->green+(int)palette->blue)/3;
347 palette++;
348 }
349 */
350 }
351
GpPutNTSC(int nColors,GpColorCell * palette)352 void GpPutNTSC(int nColors, GpColorCell *palette)
353 {
354 /*
355 while (nColors--) {
356 palette->gray=
357 (30*(int)palette->red+59*(int)palette->green+11*(int)palette->blue)/100;
358 palette++;
359 }
360 */
361 }
362
GpPutRGB(int nColors,GpColorCell * palette)363 void GpPutRGB(int nColors, GpColorCell *palette)
364 {
365 /*
366 while (nColors--) {
367 palette->red= palette->green= palette->blue= palette->gray;
368 palette++;
369 }
370 */
371 }
372
GpSetPalette(Engine * engine,GpColorCell * palette,int nColors)373 int GpSetPalette(Engine *engine, GpColorCell *palette, int nColors)
374 {
375 if (!engine) return 0;
376 if (nColors<0) {
377 palette= 0;
378 nColors= 0;
379 }
380 engine->palette= palette;
381 engine->nColors= nColors;
382 engine->colorChange= 1;
383 return engine->ChangePalette(engine);
384 }
385
GpGetPalette(Engine * engine,GpColorCell ** palette)386 int GpGetPalette(Engine *engine, GpColorCell **palette)
387 {
388 *palette= engine? engine->palette : 0;
389 return engine? engine->nColors : 0;
390 }
391
GpDumpColors(Engine * engine,int colorMode)392 int GpDumpColors(Engine *engine, int colorMode)
393 {
394 if (!engine) {
395 for (engine=GpNextActive(0) ; engine ; engine=GpNextActive(engine))
396 { engine->colorMode= colorMode; engine->colorChange= 1; }
397 } else {
398 engine->colorMode= colorMode; engine->colorChange= 1;
399 }
400 return 0;
401 }
402
403 /* ------------------------------------------------------------------------ */
404
GpClipCells(GpMap * map,GpReal * px,GpReal * qx,GpReal xmin,GpReal xmax,long ncells,long * off)405 long GpClipCells(GpMap *map, GpReal *px, GpReal *qx,
406 GpReal xmin, GpReal xmax, long ncells, long *off)
407 {
408 long imin, imax;
409 GpReal p, q, dx;
410 GpReal scale= map->scale;
411 GpReal offset= map->offset;
412
413 xmin= xmin*scale+offset;
414 xmax= xmax*scale+offset;
415 if (xmin>xmax) {GpReal tmp=xmin; xmin=xmax; xmax=tmp;}
416 p= (*px)*scale+offset;
417 q= (*qx)*scale+offset;
418
419 if (p<q && q>=xmin && p<=xmax) {
420 dx= (q-p)/(GpReal)ncells;
421 if (p<xmin) {
422 imin= (long)((xmin-p)/dx);
423 p+= dx*(GpReal)imin;
424 } else {
425 imin= 0;
426 }
427 if (q>xmax) {
428 imax= (long)((q-xmax)/dx);
429 q-= dx*(GpReal)imax;
430 imax= ncells-imax;
431 } else {
432 imax= ncells;
433 }
434 if (imax-imin<2) {
435 if (imax==imin) {
436 if (p<xmin) p= xmin;
437 if (q>xmax) q= xmax;
438 } else {
439 if (p<xmin && q>xmax) {
440 if (q-xmax > xmin-p) { q-= xmin-p; p= xmin; }
441 else { p+= q-xmax; q= xmax; }
442 }
443 }
444 }
445 } else if (p>q && p>=xmin && q<=xmax) {
446 dx= (p-q)/(GpReal)ncells;
447 if (q<xmin) {
448 imax= (long)((xmin-q)/dx);
449 q+= dx*(GpReal)imax;
450 imax= ncells-imax;
451 } else {
452 imax= ncells;
453 }
454 if (p>xmax) {
455 imin= (long)((p-xmax)/dx);
456 p-= dx*(GpReal)imin;
457 } else {
458 imin= 0;
459 }
460 if (imax-imin<2) {
461 if (imax==imin) {
462 if (q<xmin) q= xmin;
463 if (p>xmax) p= xmax;
464 } else {
465 if (q<xmin && p>xmax) {
466 if (p-xmax > xmin-q) { p-= xmin-q; q= xmin; }
467 else { q+= p-xmax; p= xmax; }
468 }
469 }
470 }
471 } else {
472 imin= 0;
473 imax= -1;
474 }
475
476 *px= p;
477 *qx= q;
478 *off= imin;
479
480 return imax-imin;
481 }
482
483 /* ------------------------------------------------------------------------ */
484
GpIntersect(const GpBox * box1,const GpBox * box2)485 int GpIntersect(const GpBox *box1, const GpBox *box2)
486 {
487 /* Algorithm assumes min<max for x and y in both boxes */
488 return box1->xmin<=box2->xmax && box1->xmax>=box2->xmin &&
489 box1->ymin<=box2->ymax && box1->ymax>=box2->ymin;
490 }
491
GpContains(const GpBox * box1,const GpBox * box2)492 int GpContains(const GpBox *box1, const GpBox *box2)
493 {
494 /* Algorithm assumes min<max for x and y in both boxes */
495 return box1->xmin<=box2->xmin && box1->xmax>=box2->xmax &&
496 box1->ymin<=box2->ymin && box1->ymax>=box2->ymax;
497 }
498
GpSwallow(GpBox * preditor,const GpBox * prey)499 void GpSwallow(GpBox *preditor, const GpBox *prey)
500 {
501 /* Algorithm assumes min<max for x and y in both boxes */
502 if (preditor->xmin>prey->xmin) preditor->xmin= prey->xmin;
503 if (preditor->xmax<prey->xmax) preditor->xmax= prey->xmax;
504 if (preditor->ymin>prey->ymin) preditor->ymin= prey->ymin;
505 if (preditor->ymax<prey->ymax) preditor->ymax= prey->ymax;
506 }
507
508 /* ------------------------------------------------------------------------ */
509
510 /* These recondite routines are required to handle editing a drawing
511 on one or more interactive engines. The restriction to few
512 routines builds in certain inefficiencies; if every drawing were always
513 associated with one interactive engine some of the inefficiency could
514 be reduced. These are not intended for external use. */
515
516 extern int gdNowRendering, gdMaxRendered;
517 int gdNowRendering= -1;
518 int gdMaxRendered= -1;
519
GdBeginDr(Drauing * drawing,GpBox * damage,int landscape)520 int GdBeginDr(Drauing *drawing, GpBox *damage, int landscape)
521 {
522 int needToRedraw= 0;
523 Engine *eng;
524
525 if (damage) {
526 /* If drawing has incurred damage, report damage to ALL engines
527 interested in the drawing (not just active engines). */
528 for (eng=GpNextEngine(0) ; eng ; eng=GpNextEngine(eng))
529 if (eng->drawing==drawing) GpDamage(eng, drawing, damage);
530 }
531
532 /* Loop on active engines to alert them that drawing is coming. */
533 for (eng=GpNextActive(0) ; eng ; eng=GpNextActive(eng)) {
534 if (eng->drawing!=drawing) {
535 /* This engine is not marked as interested in this drawing.
536 Mark it, and reset damaged and lastDrawn flags so that no
537 elements will be inhibited. */
538 eng->drawing= drawing;
539 eng->lastDrawn= -1;
540 eng->damaged= 0;
541 if (landscape != eng->landscape) {
542 eng->landscape= landscape;
543 /* This change will be detected and acted upon by the first call
544 to the ChangeMap method (GpSetTrans). */
545 }
546 /* The semantics here are subtle --
547 After a ClearDrawing, GdDetach zeroes eng->drawing in order to
548 communicate that the drawing has been cleared. Thus, the code
549 gets here on a GdDraw after the drawing has been cleared, so
550 the time has come to carry out the deferred clearing of this
551 engine's plotting surface. */
552 GpClear(eng, CONDITIONALLY);
553 needToRedraw= 1;
554
555 } else if (eng->damaged) {
556 /* This engine was interested in the drawing, which has been
557 damaged. Clear damaged area in preparation for repair work.
558 (This is redundant if the damage was due to an X windows
559 expose event, but the resulting inefficiency is very small.) */
560 eng->ClearArea(eng, &eng->damage);
561 needToRedraw= 1;
562
563 } else if (eng->lastDrawn<drawing->nElements-1) {
564 needToRedraw= 1;
565 }
566 }
567
568 gdNowRendering= gdMaxRendered= -1;
569 return needToRedraw;
570 }
571
GdBeginSy(GpBox * tickOut,GpBox * tickIn,GpBox * viewport,int number,int sysIndex)572 int GdBeginSy(GpBox *tickOut, GpBox *tickIn, GpBox *viewport,
573 int number, int sysIndex)
574 {
575 Engine *eng;
576 int value= 0;
577 long sysMask;
578
579 /* Note that this is harmless if sysIndex>2*sizeof(long)--
580 just slightly inefficient in that ticks and elements will ALWAYS
581 be drawn... This shouldn't be a practical problem. */
582 if (sysIndex>sizeof(long)) {
583 sysMask= 1 << (sysIndex-sizeof(long));
584 sysIndex= 1;
585 } else {
586 sysMask= 1 << sysIndex;
587 sysIndex= 0;
588 }
589
590 /* Loop on active engines to determine whether any require ticks or
591 elements to be drawn. Set inhibit switches for ticks. */
592 for (eng=GpNextActive(0) ; eng ; eng=GpNextActive(eng)) {
593 if ( ! (eng->systemsSeen[sysIndex] & sysMask) ) {
594 /* this engine has never seen this system */
595 value|= 3;
596 eng->inhibit= 0;
597 eng->systemsSeen[sysIndex]|= sysMask;
598
599 } else if (eng->damaged && GpIntersect(tickOut, &eng->damage)) {
600 /* engine damage touches this coordinate system--
601 redraw ticks if region between tickIn and tickOut damaged,
602 redraw elements if viewport damaged */
603 if (!tickIn || !GpContains(tickIn, &eng->damage)) {
604 value|= 2;
605 eng->inhibit= 0;
606 } else eng->inhibit= 1;
607 if (number>eng->lastDrawn || GpIntersect(viewport, &eng->damage))
608 value|= 1;
609
610 } else {
611 /* engine undamaged or damage doesn't touch this system--
612 redraw elements if any new ones, don't redraw ticks */
613 eng->inhibit= 1;
614 if (number>eng->lastDrawn) value|= 1;
615 }
616 }
617
618 return value;
619 }
620
GdBeginEl(GpBox * box,int number)621 int GdBeginEl(GpBox *box, int number)
622 {
623 Engine *eng;
624 int value= 0;
625
626 /* Loop on active engines to determine whether any require this
627 element to be drawn, and to set inhibit switches so that some
628 may draw it and others not. */
629 for (eng=GpNextActive(0) ; eng ; eng=GpNextActive(eng)) {
630 if (number>eng->lastDrawn) {
631 /* this engine hasn't seen this element before */
632 eng->inhibit= 0;
633 value= 1;
634 if (eng->damaged && gdMaxRendered<=eng->lastDrawn) {
635 /* If this is the first new element, the damage flag
636 must be reset, and ChangeMap must be called to set the
637 clip rectangle back to its undamaged boundary. */
638 eng->damaged= 0;
639 eng->ChangeMap(eng);
640 }
641
642 } else if (box && eng->damaged && GpIntersect(box, &eng->damage)) {
643 /* engine damage touches this element */
644 eng->inhibit= 0;
645 value= 1;
646
647 } else {
648 /* this element has been seen before and hasn't been damaged */
649 eng->inhibit= 1;
650 }
651
652 /* set number of element currently being drawn for GdEndDr */
653 gdNowRendering= number;
654 if (gdMaxRendered<gdNowRendering) gdMaxRendered= gdNowRendering;
655 }
656
657 return value;
658 }
659
GdEndDr(void)660 void GdEndDr(void)
661 {
662 Engine *eng;
663 /* Done with this drawing- reset inhibit, damaged, and lastDrawn flags */
664 for (eng=GpNextActive(0) ; eng ; eng=GpNextActive(eng)) {
665 if (eng->lastDrawn<gdMaxRendered) eng->lastDrawn= gdMaxRendered;
666 eng->inhibit= eng->damaged= 0;
667 }
668 }
669
GpDamage(Engine * eng,Drauing * drawing,GpBox * box)670 void GpDamage(Engine *eng, Drauing *drawing, GpBox *box)
671 {
672 if (eng->drawing!=drawing || !eng->marked) return;
673 if (eng->ClearArea==&DefaultClearArea) {
674 /* This engine doesn't need to record the damage box */
675 eng->damaged= 1;
676 } else if (eng->damaged) {
677 /* drawing is already damaged on this engine */
678 if (eng->damage.xmin>box->xmin) eng->damage.xmin= box->xmin;
679 if (eng->damage.xmax<box->xmax) eng->damage.xmax= box->xmax;
680 if (eng->damage.ymin>box->ymin) eng->damage.ymin= box->ymin;
681 if (eng->damage.ymax<box->ymax) eng->damage.ymax= box->ymax;
682 } else {
683 /* drawing is currently undamaged on this engine */
684 eng->damaged= 1;
685 eng->damage= *box;
686 }
687 }
688
GdDetach(Drauing * drawing,Engine * engine)689 void GdDetach(Drauing *drawing, Engine *engine)
690 {
691 Engine *eng;
692 for (eng=GpNextEngine(0) ; eng ; eng=GpNextEngine(eng)) {
693 if (!drawing || eng->drawing==drawing) {
694 eng->drawing= 0;
695 eng->inhibit= eng->damaged= 0;
696 eng->lastDrawn= -1;
697 }
698 }
699 }
700
701 /* ------------------------------------------------------------------------ */
702