1 /* grOGL3.c -
2 *
3 * *********************************************************************
4 * * Copyright (C) 1985, 1990 Regents of the University of California. *
5 * * Permission to use, copy, modify, and distribute this *
6 * * software and its documentation for any purpose and without *
7 * * fee is hereby granted, provided that the above copyright *
8 * * notice appear in all copies. The University of California *
9 * * makes no representations about the suitability of this *
10 * * software for any purpose. It is provided "as is" without *
11 * * express or implied warranty. Export of this software outside *
12 * * of the United States of America may require an export license. *
13 * *********************************************************************
14 *
15 * This file contains additional functions to manipulate an X window system
16 * color display. Included here are device-dependent routines to draw and
17 * erase text and draw a grid.
18 *
19 */
20
21 #include <stdio.h>
22 #include <string.h>
23
24 #include <GL/gl.h>
25 #include <GL/glx.h>
26 #include <GL/glu.h>
27
28 #include "utils/magic.h"
29 #include "utils/geometry.h"
30 #include "graphics/graphics.h"
31 #include "windows/windows.h"
32 #include "graphics/graphicsInt.h"
33 #include "textio/textio.h"
34 #include "utils/signals.h"
35 #include "utils/utils.h"
36 #include "utils/hash.h"
37 #include "dbwind/dbwind.h"
38 #include "database/fonts.h"
39 #include "grOGLInt.h"
40
41 extern Display *grXdpy;
42
43 static XFontStruct *grXFonts[4];
44 #define grSmallFont grXFonts[0]
45 #define grMediumFont grXFonts[1]
46 #define grLargeFont grXFonts[2]
47 #define grXLargeFont grXFonts[3]
48 GLuint grXBases[4];
49
50
51
52 /*---------------------------------------------------------
53 * groglDrawGrid:
54 * groglDrawGrid adds a grid to the grid layer, using the current
55 * write mask and color.
56 *
57 * Results:
58 * TRUE is returned normally. However, if the grid gets too small
59 * to be useful, then nothing is drawn and FALSE is returned.
60 *
61 * Side Effects: None.
62 *---------------------------------------------------------
63 */
64
65 bool
groglDrawGrid(prect,outline,clip)66 groglDrawGrid (prect, outline, clip)
67 Rect *prect; /* A rectangle that forms the template
68 * for the grid. Note: in order to maintain
69 * precision for the grid, the rectangle
70 * coordinates are specified in units of
71 * screen coordinates multiplied by SUBPIXEL.
72 */
73 int outline; /* the outline style */
74 Rect *clip; /* a clipping rectangle */
75 {
76 int xsize, ysize;
77 int x, y;
78 int xstart, ystart;
79 int snum, low, hi, shifted;
80
81 xsize = prect->r_xtop - prect->r_xbot;
82 ysize = prect->r_ytop - prect->r_ybot;
83 if (!xsize || !ysize)
84 return FALSE;
85 if (GRID_TOO_SMALL(xsize, ysize))
86 return FALSE;
87
88 xstart = prect->r_xbot % xsize;
89 while (xstart < clip->r_xbot << SUBPIXELBITS) xstart += xsize;
90 ystart = prect->r_ybot % ysize;
91 while (ystart < clip->r_ybot << SUBPIXELBITS) ystart += ysize;
92
93 groglSetLineStyle(outline);
94
95 glBegin(GL_LINES);
96
97 snum = 0;
98 low = clip->r_ybot;
99 hi = clip->r_ytop;
100 for (x = xstart; x < (clip->r_xtop + 1) << SUBPIXELBITS; x += xsize)
101 {
102 shifted = x >> SUBPIXELBITS;
103 glVertex2i(shifted, low);
104 glVertex2i(shifted, hi);
105 snum++;
106 }
107
108 snum = 0;
109 low = clip->r_xbot;
110 hi = clip->r_xtop;
111 for (y = ystart; y < (clip->r_ytop + 1) << SUBPIXELBITS; y += ysize)
112 {
113 shifted = y >> SUBPIXELBITS;
114 glVertex2i(low, shifted);
115 glVertex2i(hi, shifted);
116 snum++;
117 }
118
119 glEnd();
120 return TRUE;
121 }
122
123
124 /*---------------------------------------------------------
125 * groglPreLoadFont
126 * This local routine loads the X fonts used by Magic.
127 * At this time, we need the font information to size
128 * the window (making room for the title at the top),
129 * but with no rendering context set (no window to
130 * draw to) we defer transferring the font bitmaps to
131 * OpenGL display lists until later.
132 *
133 * Results: Success/Fail
134 *
135 * Side Effects: None.
136 *---------------------------------------------------------
137 */
138
139 bool
groglPreLoadFont()140 groglPreLoadFont()
141 {
142 XFontStruct *fontInfo;
143 int i;
144 char *s;
145 char *unable = "Unable to load font";
146
147 static char *fontnames[4] = {
148 X_FONT_SMALL,
149 X_FONT_MEDIUM,
150 X_FONT_LARGE,
151 X_FONT_XLARGE };
152 static char *optionnames[4] = {
153 "small",
154 "medium",
155 "large",
156 "xlarge"};
157
158 for (i = 0; i < 4; i++) {
159 s = XGetDefault(grXdpy,"magic",optionnames[i]);
160 if (s) fontnames[i] = s;
161 if ((fontInfo = XLoadQueryFont(grXdpy, fontnames[i])) == NULL) {
162 TxError("%s %s\n",unable,fontnames[i]);
163 if ((grXFonts[i]= XLoadQueryFont(grXdpy,GR_DEFAULT_FONT))==NULL) {
164 TxError("%s %s\n",unable,GR_DEFAULT_FONT);
165 return FALSE;
166 }
167 }
168 grXFonts[i] = fontInfo;
169 }
170 return TRUE;
171 }
172
173
174 /*---------------------------------------------------------
175 * groglLoadFont
176 * This local routine transfers the X font bitmaps
177 * into OpenGL display lists for simple text
178 * rendering.
179 *
180 * Results: Success/Fail.
181 *
182 * Side Effects: None.
183 *---------------------------------------------------------
184 */
185
186 bool
groglLoadFont()187 groglLoadFont()
188 {
189 XFontStruct *fontInfo;
190 Font id;
191 unsigned int first, last, i;
192
193 for (i = 0; i < 4; i++) {
194 fontInfo = grXFonts[i];
195 id = fontInfo->fid;
196 first = fontInfo->min_char_or_byte2;
197 last = fontInfo->max_char_or_byte2;
198
199 grXBases[i] = glGenLists(last+1);
200 if (grXBases[i] == 0) {
201 TxError("Out of display lists!\n");
202 return FALSE;
203 }
204 glXUseXFont(id, first, last-first+1, grXBases[i]+first);
205 }
206 return TRUE;
207 }
208
209
210 /*---------------------------------------------------------
211 * groglSetCharSize:
212 * This local routine sets the character size in the display,
213 * if necessary.
214 *
215 * Results: None.
216 *
217 * Side Effects: None.
218 *---------------------------------------------------------
219 */
220
221 void
groglSetCharSize(size)222 groglSetCharSize (size)
223 int size; /* Width of characters */
224 {
225 oglCurrent.fontSize = size;
226
227 switch (size) {
228 case GR_TEXT_DEFAULT:
229 case GR_TEXT_SMALL:
230 oglCurrent.font = grSmallFont;
231 break;
232 case GR_TEXT_MEDIUM:
233 oglCurrent.font = grMediumFont;
234 break;
235 case GR_TEXT_LARGE:
236 oglCurrent.font = grLargeFont;
237 break;
238 case GR_TEXT_XLARGE:
239 oglCurrent.font = grXLargeFont;
240 break;
241 default:
242 TxError("%s%d\n", "groglSetCharSize: Unknown character size ",
243 size );
244 break;
245 break;
246 }
247 }
248
249
250 /*
251 * ----------------------------------------------------------------------------
252 * GrOGLTextSize --
253 *
254 * Determine the size of a text string.
255 *
256 * Results:
257 * None.
258 *
259 * Side effects:
260 * A rectangle is filled in that is the size of the text in pixels.
261 * The origin (0, 0) of this rectangle is located on the baseline
262 * at the far left side of the string.
263 * ----------------------------------------------------------------------------
264 */
265
266 void
GrOGLTextSize(text,size,r)267 GrOGLTextSize(text, size, r)
268 char *text;
269 int size;
270 Rect *r;
271 {
272 XCharStruct overall;
273 XFontStruct *font;
274 int dir,fa,fd;
275
276 switch (size) {
277 case GR_TEXT_DEFAULT:
278 case GR_TEXT_SMALL:
279 font = grSmallFont;
280 break;
281 case GR_TEXT_MEDIUM:
282 font = grMediumFont;
283 break;
284 case GR_TEXT_LARGE:
285 font = grLargeFont;
286 break;
287 case GR_TEXT_XLARGE:
288 font = grXLargeFont;
289 break;
290 default:
291 TxError("%s%d\n", "GrOGLTextSize: Unknown character size ",
292 size );
293 break;
294 }
295 if (font == NULL) return;
296 XTextExtents(font, text, strlen(text), &dir, &fa, &fd, &overall);
297
298 r->r_ytop = overall.ascent;
299 r->r_ybot = -overall.descent;
300 r->r_xtop = overall.width - overall.lbearing;
301 r->r_xbot = -overall.lbearing - 1;
302 }
303
304
305 /*
306 * ----------------------------------------------------------------------------
307 * GrOGLReadPixel --
308 *
309 * Read one pixel from the screen.
310 *
311 * Results:
312 * An integer containing the pixel's color.
313 * (Except OpenGL has no such function, so we just return 0)
314 *
315 * Side effects:
316 * none.
317 *
318 * ----------------------------------------------------------------------------
319 */
320
321 int
GrOGLReadPixel(w,x,y)322 GrOGLReadPixel (w, x, y)
323 MagWindow *w;
324 int x,y; /* the location of a pixel in screen coords */
325 {
326 return 0;
327 }
328
329
330 /*
331 * ----------------------------------------------------------------------------
332 * GrOGLBitBlt --
333 *
334 * Copy information from one part of the screen to the other.
335 *
336 * Results:
337 * None.
338 *
339 * Side effects:
340 * changes the screen.
341 * ----------------------------------------------------------------------------
342 */
343
344 void
GrOGLBitBlt(r,p)345 GrOGLBitBlt(r, p)
346 Rect *r;
347 Point *p;
348 {
349 glCopyPixels(r->r_xbot, r->r_ybot, r->r_xtop - r->r_xbot + 1,
350 r->r_ytop - r->r_ybot + 1, GL_COLOR);
351 }
352
353 #ifdef VECTOR_FONTS
354
355 /*
356 *----------------------------------------------------------------------
357 *
358 * Technically, there should be no self-intersecting polygons in outline
359 * fonts. However, decomposition of bezier curves into line segments
360 * may occasionally produce one, so it needs to be handled.
361 *----------------------------------------------------------------------
362 */
363
364 void
myCombine(GLdouble coords[3],GLdouble * vertex_data[4],GLfloat weight[4],GLdouble ** outData,void * dataptr)365 myCombine(GLdouble coords[3], GLdouble *vertex_data[4],
366 GLfloat weight[4], GLdouble **outData, void *dataptr)
367 {
368 /* This needs to be free'd at the end of gluTessEndPolygon()! */
369 GLdouble *new = (GLdouble *)mallocMagic(2 * sizeof(GLdouble));
370 new[0] = coords[0];
371 new[1] = coords[1];
372 *outData = new;
373 /* Diagnostic */
374 TxError("Intersecting polygon in char \"%c\" at %g %g!\n",
375 *((char *)dataptr), coords[0], coords[1]);
376 }
377
378 /*
379 *----------------------------------------------------------------------
380 * Draw a text character
381 * This routine differs from grtoglFillPolygon() in that it uses the
382 * glu library to handle non-convex polygons as may appear in font
383 * outlines.
384 *----------------------------------------------------------------------
385 */
386
387 void
groglDrawCharacter(clist,tc,pixsize)388 groglDrawCharacter(clist, tc, pixsize)
389 FontChar *clist;
390 unsigned char tc;
391 int pixsize;
392 {
393 Point *tp;
394 int np, nptotal;
395 int i, j;
396 static GLUtesselator *tess = NULL;
397 static GLdouble *v = NULL;
398 static int maxnp = 0;
399 FontChar *ccur;
400
401 if (pixsize < 5) return; /* Label too small to be useful */
402
403 if (tess == NULL)
404 {
405 tess = gluNewTess();
406 gluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)glBegin);
407 gluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)glVertex3dv);
408 gluTessCallback(tess, GLU_TESS_END, (_GLUfuncptr)glEnd);
409 gluTessCallback(tess, GLU_TESS_COMBINE_DATA, (_GLUfuncptr)myCombine);
410 }
411 // Boundary-only does not look particularly good. . .
412 gluTessProperty(tess, GLU_TESS_BOUNDARY_ONLY, GL_FALSE);
413
414 nptotal = 0;
415 for (ccur = clist; ccur != NULL; ccur = ccur->fc_next)
416 nptotal += ccur->fc_numpoints;
417
418 if (nptotal > maxnp)
419 {
420 if (v != NULL) freeMagic((char *)v);
421 maxnp = nptotal;
422 v = (GLdouble *)mallocMagic(nptotal * 3 * sizeof(GLdouble));
423 }
424
425 j = 0;
426 for (ccur = clist; ccur != NULL; ccur = ccur->fc_next)
427 {
428 tp = ccur->fc_points;
429 np = ccur->fc_numpoints;
430
431 for (i = 0; i < np; i++, j += 3) {
432 v[j] = tp[i].p_x;
433 v[j + 1] = tp[i].p_y;
434 v[j + 2] = 0;
435 }
436 }
437
438 gluTessBeginPolygon(tess, (GLvoid *)(&tc));
439 j = 0;
440 for (ccur = clist; ccur != NULL; ccur = ccur->fc_next)
441 {
442 np = ccur->fc_numpoints;
443 gluTessBeginContour(tess);
444 for (i = 0; i < np; i++, j += 3) {
445 gluTessVertex(tess, &v[j], &v[j]);
446 }
447 gluTessEndContour(tess);
448 }
449 gluTessEndPolygon(tess);
450 }
451
452 /*---------------------------------------------------------
453 * groglFontText:
454 *
455 * This routine draws text from font vectors using the
456 * font vector routines in DBlabel.c. Text is clipped
457 * to the clipping rectangle.
458 *
459 * For speed, we should be transferring the font
460 * vectors into OpenGL display lists!
461 *
462 *---------------------------------------------------------
463 */
464
465 void
groglFontText(text,font,size,rotate,pos,clip,obscure)466 groglFontText(text, font, size, rotate, pos, clip, obscure)
467 char *text; /* The text to be drawn */
468 int font; /* Font to use from fontList */
469 int size; /* Pixel size of the font */
470 int rotate; /* Text rotation */
471 Point *pos; /* Text base position */
472 Rect *clip; /* Clipping area */
473 LinkedRect *obscure; /* List of obscuring areas */
474 {
475 char *tptr;
476 Point *coffset; /* vector to next character */
477 Rect *cbbox;
478 GLfloat fsize, matvals[16];
479 FontChar *clist;
480 int cheight, baseline;
481 float tmp;
482
483 /* Keep it simple for now---ignore clip and obscure */
484
485 glDisable(GL_BLEND);
486 glPushMatrix();
487 glTranslated(pos->p_x, pos->p_y, 0);
488 glRotated(rotate, 0, 0, 1);
489
490 /* Get label size */
491 cbbox = &DBFontList[font]->mf_extents;
492
493 fsize = (GLfloat)size / (GLfloat)cbbox->r_ytop;
494 glScalef(fsize, fsize, 1.0);
495
496 /* Adjust to baseline */
497 baseline = 0;
498 for (tptr = text; *tptr != '\0'; tptr++)
499 {
500 DBFontChar(font, *tptr, NULL, NULL, &cbbox);
501 if (cbbox->r_ybot < baseline)
502 baseline = cbbox->r_ybot;
503 }
504 glTranslated(0, -baseline, 0);
505
506 for (tptr = text; *tptr != '\0'; tptr++)
507 {
508 DBFontChar(font, *tptr, &clist, &coffset, NULL);
509 groglDrawCharacter(clist, *tptr, size);
510 glTranslated(coffset->p_x, coffset->p_y, 0);
511 }
512 glPopMatrix();
513 }
514
515 #endif /* VECTOR_FONTS */
516
517 static GC grXcopyGC = (GC)NULL;
518
519 /*
520 * ----------------------------------------------------------------------------
521 * groglFreeBackingStore --
522 * Free up Pixmap memory for a backing store cell.
523 *
524 * Results:
525 * None.
526 *
527 * Side effects:
528 * memory Free'd
529 * ----------------------------------------------------------------------------
530 */
531
532 void
groglFreeBackingStore(MagWindow * window)533 groglFreeBackingStore(MagWindow *window)
534 {
535 Pixmap pmap = (Pixmap)window->w_backingStore;
536 if (pmap == (Pixmap)NULL) return;
537 XFreePixmap(grXdpy, pmap);
538 window->w_backingStore = (ClientData)NULL;
539 /* XFreeGC(grXdpy, grXcopyGC); */
540 /* TxPrintf("groglFreeBackingStore called\n"); */
541 }
542
543 /*
544 * ----------------------------------------------------------------------------
545 * groglCreateBackingStore --
546 * Create Pixmap memory for a backing store cell and copy data
547 * from the window into it.
548 *
549 * Results:
550 * None.
551 *
552 * Side effects:
553 * memory Allocated.
554 *
555 * ----------------------------------------------------------------------------
556 */
557
558 void
groglCreateBackingStore(MagWindow * w)559 groglCreateBackingStore(MagWindow *w)
560 {
561 Pixmap pmap;
562 Window wind = (Window)w->w_grdata;
563 unsigned int width, height;
564 GC gc;
565 XGCValues gcValues;
566
567 /* ignore for all windows except layout */
568 if (w->w_client != DBWclientID) return;
569
570 /* deferred */
571 if (w->w_grdata == (Window)NULL) return;
572
573 width = w->w_screenArea.r_xtop - w->w_screenArea.r_xbot;
574 height = w->w_screenArea.r_ytop - w->w_screenArea.r_ybot;
575
576 if (w->w_backingStore != (ClientData)NULL) groglFreeBackingStore(w);
577
578 if (grXcopyGC == (GC)NULL)
579 {
580 gcValues.graphics_exposures = FALSE;
581 grXcopyGC = XCreateGC(grXdpy, wind, GCGraphicsExposures, &gcValues);
582 }
583
584 pmap = XCreatePixmap(grXdpy, wind, width, height, oglCurrent.depth);
585 w->w_backingStore = (ClientData)pmap;
586
587 /* TxPrintf("groglCreateBackingStore area %d %d %d %d\n",
588 w->w_screenArea.r_xbot, w->w_screenArea.r_ybot,
589 w->w_screenArea.r_xtop, w->w_screenArea.r_ytop); */
590 }
591
592 /*
593 * ----------------------------------------------------------------------------
594 * groglGetBackingStore --
595 * Copy data from a backing store Pixmap into the indicated window.
596 *
597 * Results:
598 * TRUE if backing store was copied successfully, FALSE if not.
599 *
600 * Side effects:
601 * Data copied into Pixmap memory.
602 *
603 * ----------------------------------------------------------------------------
604 */
605
606 bool
groglGetBackingStore(MagWindow * w,Rect * area)607 groglGetBackingStore(MagWindow *w, Rect *area)
608 {
609 Pixmap pmap;
610 Window wind = (Window)w->w_grdata;
611 unsigned int width, height;
612 int ybot;
613 int xoff, yoff;
614 Rect r;
615
616 pmap = (Pixmap)w->w_backingStore;
617 if (pmap == (Pixmap)NULL)
618 return FALSE;
619
620 /* Make a local copy of area so we don't disturb the original */
621 r = *area;
622 GeoClip(&r, &(w->w_screenArea));
623
624 width = r.r_xtop - r.r_xbot;
625 height = r.r_ytop - r.r_ybot;
626 ybot = glTransY(w, r.r_ytop);
627
628 xoff = w->w_screenArea.r_xbot - w->w_allArea.r_xbot;
629 yoff = w->w_allArea.r_ytop - w->w_screenArea.r_ytop;
630
631 XCopyArea(grXdpy, pmap, wind, grXcopyGC, r.r_xbot - xoff, ybot - yoff,
632 width, height, r.r_xbot, ybot);
633
634 /* TxPrintf("groglGetBackingStore %d %d %d %d\n",
635 r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop); */
636 return TRUE;
637 }
638
639 /*
640 * ----------------------------------------------------------------------------
641 * groglScrollBackingStore --
642 * Enable fast scrolling by shifting part of the backing store
643 * from one position to another, with the amount of shift indicated
644 * by the X and/or Y value of the indicated point.
645 *
646 * Results:
647 * TRUE on success, FALSE on failure.
648 *
649 * Side effects:
650 * Data shifted in Pixmap memory.
651 *
652 * ----------------------------------------------------------------------------
653 */
654
655 bool
groglScrollBackingStore(MagWindow * w,Point * shift)656 groglScrollBackingStore(MagWindow *w, Point *shift)
657 {
658 Pixmap pmap;
659 unsigned int width, height;
660 int xorigin, yorigin, xshift, yshift;
661
662 pmap = (Pixmap)w->w_backingStore;
663 if (pmap == (Pixmap)NULL)
664 {
665 TxPrintf("groglScrollBackingStore %d %d failure\n",
666 shift->p_x, shift->p_y);
667 return FALSE;
668 }
669
670 width = w->w_screenArea.r_xtop - w->w_screenArea.r_xbot;
671 height = w->w_screenArea.r_ytop - w->w_screenArea.r_ybot;
672 xorigin = 0;
673 yorigin = 0;
674 xshift = shift->p_x;
675 yshift = -shift->p_y;
676
677 if (xshift > 0)
678 width -= xshift;
679 else if (xshift < 0)
680 {
681 width += xshift;
682 xorigin = -xshift;
683 xshift = 0;
684 }
685 if (yshift > 0)
686 height -= yshift;
687 else if (yshift < 0)
688 {
689 height += yshift;
690 yorigin = -yshift;
691 yshift = 0;
692 }
693
694 XCopyArea(grXdpy, pmap, pmap, grXcopyGC, xorigin, yorigin, width, height,
695 xshift, yshift);
696
697 /* TxPrintf("groglScrollBackingStore %d %d\n", shift->p_x, shift->p_y); */
698 return TRUE;
699 }
700
701 /*
702 * ----------------------------------------------------------------------------
703 * groglPutBackingStore --
704 * Copy data from the window into backing store.
705 *
706 * Results:
707 * None.
708 *
709 * Side effects:
710 * Graphics drawing into the window.
711 * ----------------------------------------------------------------------------
712 */
713
714 void
groglPutBackingStore(MagWindow * w,Rect * area)715 groglPutBackingStore(MagWindow *w, Rect *area)
716 {
717 Pixmap pmap = (Pixmap)w->w_backingStore;
718 Window wind = (Window)w->w_grdata;
719 unsigned int width, height;
720 int ybot, xoff, yoff;
721
722 if (pmap == (Pixmap)NULL) return;
723
724 /* Attempting to write backing store into an obscured */
725 /* window (which we keep track of with Visibility events) */
726 /* causes backing store to be invalid. */
727
728 if (w->w_flags & WIND_OBSCURED)
729 {
730 groglFreeBackingStore(w);
731 w->w_backingStore = (ClientData)NULL;
732 return;
733 }
734
735 width = area->r_xtop - area->r_xbot;
736 height = area->r_ytop - area->r_ybot;
737 ybot = glTransY(w, area->r_ytop);
738
739 xoff = w->w_screenArea.r_xbot - w->w_allArea.r_xbot;
740 yoff = w->w_allArea.r_ytop - w->w_screenArea.r_ytop;
741
742 XCopyArea(grXdpy, wind, pmap, grXcopyGC, area->r_xbot, ybot,
743 width, height, area->r_xbot - xoff, ybot - yoff);
744
745 /* TxPrintf("groglPutBackingStore %d %d %d %d\n",
746 area->r_xbot, area->r_ybot, area->r_xtop, area->r_ytop); */
747 }
748
749
750 /*---------------------------------------------------------
751 * groglPutText:
752 * (modified on SunPutText)
753 *
754 * This routine puts a chunk of text on the screen in the current
755 * color, size, etc. The caller must ensure that it fits on
756 * the screen -- no clipping is done except to the obscuring rectangle
757 * list and the clip rectangle.
758 *
759 * Results:
760 * none.
761 *
762 * Side Effects:
763 * The text is drawn on the screen.
764 *
765 *---------------------------------------------------------
766 */
767
768 void
groglPutText(text,pos,clip,obscure)769 groglPutText (text, pos, clip, obscure)
770 char *text; /* The text to be drawn. */
771 Point *pos; /* A point located at the leftmost point of
772 * the baseline for this string.
773 */
774 Rect *clip; /* A rectangle to clip against */
775 LinkedRect *obscure; /* A list of obscuring rectangles */
776
777 {
778 Rect location;
779 Rect overlap;
780 Rect textrect;
781 LinkedRect *ob;
782 void grOGLGeoSub();
783 int i;
784 float tscale;
785
786 GrOGLTextSize(text, oglCurrent.fontSize, &textrect);
787
788 location.r_xbot = pos->p_x + textrect.r_xbot;
789 location.r_xtop = pos->p_x + textrect.r_xtop;
790 location.r_ybot = pos->p_y + textrect.r_ybot;
791 location.r_ytop = pos->p_y + textrect.r_ytop;
792
793 /* erase parts of the bitmap that are obscured */
794 for (ob = obscure; ob != NULL; ob = ob->r_next)
795 {
796 if (GEO_TOUCH(&ob->r_r, &location))
797 {
798 overlap = location;
799 GeoClip(&overlap, &ob->r_r);
800 grOGLGeoSub(&location, &overlap);
801 }
802 }
803
804 overlap = location;
805 GeoClip(&overlap, clip);
806
807 /* copy the text to the color screen */
808 if ((overlap.r_xbot < overlap.r_xtop)&&(overlap.r_ybot <= overlap.r_ytop))
809 {
810 glScissor(overlap.r_xbot, overlap.r_ybot, overlap.r_xtop - overlap.r_xbot,
811 overlap.r_ytop - overlap.r_ybot);
812 glEnable(GL_SCISSOR_TEST);
813 glDisable(GL_BLEND);
814 glRasterPos2i(pos->p_x, pos->p_y);
815 glListBase(grXBases[(oglCurrent.fontSize == GR_TEXT_DEFAULT) ?
816 GR_TEXT_SMALL : oglCurrent.fontSize]);
817 glCallLists(strlen(text), GL_UNSIGNED_BYTE, (unsigned char *)text);
818 glDisable(GL_SCISSOR_TEST);
819 }
820 }
821
822
823 /* grOGLGeoSub:
824 * return the tallest sub-rectangle of r not obscured by area
825 * area must be within r.
826 */
827
828 void
grOGLGeoSub(r,area)829 grOGLGeoSub(r, area)
830 Rect *r; /* Rectangle to be subtracted from. */
831 Rect *area; /* Area to be subtracted. */
832
833 {
834 if (r->r_xbot == area->r_xbot) r->r_xbot = area->r_xtop;
835 else
836 if (r->r_xtop == area->r_xtop) r->r_xtop = area->r_xbot;
837 else
838 if (r->r_ybot <= area->r_ybot) r->r_ybot = area->r_ytop;
839 else
840 if (r->r_ytop == area->r_ytop) r->r_ytop = area->r_ybot;
841 else
842 r->r_xtop = area->r_xbot;
843 }
844