1 /* grOGL5.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  *	Manipulate the programable cursor on the graphics display.
16  *
17  */
18 
19 #include <stdio.h>
20 
21 #include <GL/gl.h>
22 #include <GL/glx.h>
23 
24 #include "utils/magic.h"
25 #include "utils/styles.h"
26 #include "utils/hash.h"
27 #include "textio/textio.h"
28 #include "utils/geometry.h"
29 #include "graphics/graphics.h"
30 #include "graphics/glyphs.h"
31 #include "windows/windows.h"
32 #include "graphics/graphicsInt.h"
33 #include "grOGLInt.h"
34 
35 extern HashTable	grOGLWindowTable;
36 extern Display *grXdpy;
37 extern int	grXscrn;
38 
39 Cursor grCursors[MAX_CURSORS];
40 
41 
42 /*
43  * ----------------------------------------------------------------------------
44  * GrOGLDrawGlyph --
45  *
46  *	Draw one glyph on the display.
47  *
48  * Results:
49  *	None.
50  *
51  * Side effects:
52  *	Draws pixels.
53  * ----------------------------------------------------------------------------
54  */
55 
56 void
GrOGLDrawGlyph(gl,p)57 GrOGLDrawGlyph (gl, p)
58     GrGlyph *gl;		/* A single glyph */
59     Point *p;			/* screen pos of lower left corner */
60 {
61     Rect bBox;
62     bool anyObscure;
63     LinkedRect *ob;
64 
65     GR_CHECK_LOCK();
66 
67     /* We're going to change the graphics state without affecting */
68     /* the standard color and mask saved values, so we had better */
69     /* flush all rects & lines first.                             */
70     GR_X_FLUSH_BATCH();
71 
72     bBox.r_ll = *p;
73     bBox.r_xtop = p->p_x + gl->gr_xsize - 1;
74     bBox.r_ytop = p->p_y + gl->gr_ysize - 1;
75 
76     anyObscure = FALSE;
77     for (ob = grCurObscure; ob != NULL; ob = ob->r_next) {
78 	if (GEO_TOUCH( &(ob->r_r), &bBox)) {
79 	    anyObscure = TRUE;
80 	    break;
81 	}
82     }
83 
84     if ((!anyObscure) && (GEO_SURROUND(&grCurClip, &bBox)) ) {
85 	int *pixelp, x, y;
86 
87 	/* no clipping, try to go quickly */
88 	pixelp = gl->gr_pixels;
89 	for (y = 0; y < gl->gr_ysize; y++) {
90 	    int x1, y1;
91 
92 	    y1 = bBox.r_ybot + y;
93 	    for (x = 0; x < gl->gr_xsize; x++) {
94 		int color, red, green, blue, mask;
95 		if (*pixelp != 0) {
96 		    mask = GrStyleTable[*pixelp].color << 1;
97 	            color = GrStyleTable[*pixelp].color;
98 		    x1 = bBox.r_xbot + x;
99 		    GrGetColor(color, &red, &green, &blue);
100 		    glColor4ub((GLubyte)red, (GLubyte)green, (GLubyte)blue,
101 					(GLubyte)mask);
102 		    glBegin(GL_POINTS);
103 		    glVertex2i((GLint)x1, (GLint)y1);
104 		    glEnd();
105 		}
106 		pixelp++;
107 	    }
108 	}
109     } else {
110 	/* do pixel by pixel clipping */
111 	int y, yloc;
112 
113 	yloc = bBox.r_ybot;
114 	for (y = 0; y < gl->gr_ysize; y++) {
115 	    int startx, endx;
116 	    if ( (yloc <= grCurClip.r_ytop) && (yloc >= grCurClip.r_ybot) ) {
117 		int laststartx;
118 		laststartx = bBox.r_xbot - 1;
119 		for (startx = bBox.r_xbot; startx <= bBox.r_xtop;
120 			startx = endx + 1) {
121 		    int *pixelp;
122 
123 		    startx = MAX(startx, grCurClip.r_xbot);
124 		    endx = MIN(bBox.r_xtop, grCurClip.r_xtop);
125 
126 		    if (anyObscure) {
127 			for (ob = grCurObscure; ob != NULL; ob = ob->r_next) {
128 			    if ( (ob->r_r.r_ybot <= yloc) &&
129 				 (ob->r_r.r_ytop >= yloc) ) {
130 				if (ob->r_r.r_xbot <= startx)
131 				    startx = MAX(startx, ob->r_r.r_xtop + 1);
132 				else if (ob->r_r.r_xbot <= endx)
133 				    endx = MIN(endx, ob->r_r.r_xbot - 1);
134 			    }
135 			}
136 		    }
137 
138 		    /* stop if we aren't advancing */
139 		    if (startx == laststartx) break;
140 		    laststartx = startx;
141 		    if (startx > endx) continue;
142 
143 		    /* draw a section of this scan line */
144 		    pixelp = &( gl->gr_pixels[y*gl->gr_xsize +
145 			    (startx - bBox.r_xbot)]);
146 		    for ( ; startx <= endx; startx++) {
147 			int color, red, green, blue, mask;
148 			if (*pixelp != 0) {
149 			    mask = GrStyleTable[*pixelp].mask << 1;
150 			    color = GrStyleTable[*pixelp].color;
151 			    GrGetColor(color, &red, &green, &blue);
152 			    glColor4ub((GLubyte)red, (GLubyte)green,
153 					(GLubyte)blue, (GLubyte)mask);
154 			    glBegin(GL_POINTS);
155 			    glVertex2i((GLint)startx, (GLint)yloc);
156 			    glEnd();
157 			}
158 			pixelp++;
159 		    }
160 		    startx = endx + 1;
161 		}
162 	    }
163 	    yloc++;
164 	}
165     }
166 }
167 
168 
169 /*
170  * ----------------------------------------------------------------------------
171  * groglDefineCursor:
172  *
173  * Use X cursors on top of the OpenGL window
174  *
175  * Results:
176  *	None.
177  *
178  * Side effects:
179  *	The given matrix is stored in the graphics display, and it can be
180  *	used as the cursor by calling GrSetCursor.
181  * ----------------------------------------------------------------------------
182  */
183 
184 void
groglDefineCursor(glyphs)185 groglDefineCursor(glyphs)
186     GrGlyphs *glyphs;
187 {
188     int glyphnum;
189     Rect oldClip;
190     int red, green, blue;
191     Pixmap source,mask;
192     XColor curcolor;
193 
194 
195     if (glyphs->gr_num <= 0) return;
196 
197     if (glyphs->gr_num > MAX_CURSORS)
198     {
199 	TxError("X only has room for %d cursors\n", MAX_CURSORS);
200 	return;
201     }
202 
203     /* expand clipping amount for off-screen access on the X */
204     GrLock(GR_LOCK_SCREEN, FALSE);
205     oldClip = grCurClip;
206     grCurClip = GrScreenRect;
207     grCurClip.r_ytop += 16;
208 
209     /* what color should the cursor be?  The following makes it the
210        opposite of what the background "mostly" is.
211     */
212     GrGetColor(GrStyleTable[STYLE_TRANSPARENT].color, &red, &green, &blue);
213 
214     if (red + green + blue > 0x180)  /* (0x180 = 128 * 3) */
215     {
216     	 curcolor.pixel = BlackPixel(grXdpy,grXscrn);
217 	 curcolor.red = 0;
218 	 curcolor.green = 0;
219 	 curcolor.blue = 0;
220 	 curcolor.flags |= DoRed|DoGreen|DoBlue;
221     }
222     else
223     {
224     	 curcolor.pixel = WhitePixel(grXdpy,grXscrn);
225 	 curcolor.red = 65535;
226 	 curcolor.green = 65535;
227 	 curcolor.blue = 65535;
228 	 curcolor.flags |= DoRed|DoGreen|DoBlue;
229     }
230 
231     /* enter the glyphs */
232     for (glyphnum = 0; glyphnum < glyphs->gr_num; glyphnum++) {
233 	int *p;
234 	GrGlyph *g;
235 	int x, y;
236 	unsigned char curs[32];
237 
238 	g = glyphs->gr_glyph[glyphnum];
239 	if ((g->gr_xsize != 16) || (g->gr_ysize != 16)) {
240 	    TxError("Cursors for the X must be 16 X 16 pixels.\n");
241 	    return;
242 	}
243 
244 	/* Perform transposition on the glyph matrix since X displays
245 	 * the least significant bit on the left hand side.
246 	 */
247 	p = &(g->gr_pixels[0]);
248 	for (y = 0; y < 32; y += 2) {
249 	    int i;
250 
251 	    curs[i = 31 - y - 1] = 0;
252 	    for (x = 0; x < 8; x++)
253 	    {
254 		if (GrStyleTable[*p].color != 0)
255 		{
256 		     curs[i] |= 1 << x;
257 		}
258 		p++;
259 	    }
260 	    curs[i += 1] = 0;
261 	    for (x = 0; x < 8; x++)
262 	    {
263 		if (GrStyleTable[*p].color != 0)
264 		{
265 		     curs[i] |= 1 << x;
266 		}
267 		p++;
268 	    }
269 	}
270 	source = XCreateBitmapFromData(grXdpy, XDefaultRootWindow(grXdpy),
271 				       (char *)curs, 16, 16);
272 	mask = XCreateBitmapFromData(grXdpy, XDefaultRootWindow(grXdpy),
273 				     (char *)curs, 16, 16);
274 	grCursors[glyphnum] = XCreatePixmapCursor(grXdpy, source, mask,
275 						  &curcolor, &curcolor,
276 						  g->gr_origin.p_x,
277 						  (15 - g->gr_origin.p_y));
278     }
279 
280     /* Restore clipping */
281     grCurClip = oldClip;
282     GrUnlock(GR_LOCK_SCREEN);
283 }
284 
285 
286 /*
287  * ----------------------------------------------------------------------------
288  * GrOGLSetCursor:
289  *
290  *	Make the cursor be a new pattern, as defined in the display styles file.
291  *
292  * Results:
293  *	None.
294  *
295  * Side effects:
296  *	When the cursor is turned back on it will take on the new pattern.
297  * ----------------------------------------------------------------------------
298  */
299 
300 void
GrOGLSetCursor(cursorNum)301 GrOGLSetCursor(cursorNum)
302 int cursorNum;		/* The cursor number as defined in the display
303 		         * styles file.
304 		         */
305 {
306     HashEntry	*entry;
307     HashSearch	hs;
308 
309     if (cursorNum >= MAX_CURSORS)
310     {
311 	TxError("No such cursor!\n");
312 	return;
313     }
314 
315     oglCurrent.cursor = grCursors[cursorNum];
316 
317     HashStartSearch(&hs);
318     while (entry = HashNext(&grOGLWindowTable, &hs))
319 	if (HashGetValue(entry))
320 	    XDefineCursor(grXdpy, (Window)entry->h_key.h_ptr, oglCurrent.cursor);
321 
322     /* The following is necessary to make sure the cursor is changed NOW */
323     glXWaitX();
324 }
325