Merge commit 'origin/master' into gallium-0.2
[mesa.git] / src / glut / fbdev / cursor.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5
4 * Copyright (C) 1995-2006 Brian Paul
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the Free
18 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 /*
22 * Library for glut using mesa fbdev driver
23 *
24 * Written by Sean D'Epagnier (c) 2006
25 */
26
27 /* these routines are written to access graphics memory directly, not using mesa
28 to render the cursor, this is faster, it would be good to use a hardware
29 cursor if it exists instead */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <inttypes.h>
34 #include <string.h>
35
36 #include <linux/fb.h>
37
38 #include <GL/glut.h>
39
40 #include "internal.h"
41 #include "cursors.h"
42
43 int CurrentCursor = GLUT_CURSOR_LEFT_ARROW;
44
45 static int LastMouseX, LastMouseY;
46 static unsigned char *MouseBuffer;
47
48 void InitializeCursor(void)
49 {
50 if(!MouseBuffer && (MouseBuffer = malloc(CURSOR_WIDTH * CURSOR_HEIGHT
51 * VarInfo.bits_per_pixel / 8)) == NULL) {
52 sprintf(exiterror, "malloc failure\n");
53 exit(0);
54 }
55
56 MouseX = VarInfo.xres / 2;
57 MouseY = VarInfo.yres / 2;
58 }
59
60 void EraseCursor(void)
61 {
62 int off = LastMouseY * FixedInfo.line_length
63 + LastMouseX * VarInfo.bits_per_pixel / 8;
64 int stride = CURSOR_WIDTH * VarInfo.bits_per_pixel / 8;
65 int i;
66
67 unsigned char *src = MouseBuffer;
68
69 if(!MouseVisible || CurrentCursor < 0 || CurrentCursor >= NUM_CURSORS)
70 return;
71
72 for(i = 0; i<CURSOR_HEIGHT; i++) {
73 memcpy(BackBuffer + off, src, stride);
74 src += stride;
75 off += FixedInfo.line_length;
76 }
77 }
78
79 static void SaveCursor(int x, int y)
80 {
81 int bypp, off, stride, i;
82 unsigned char *src = MouseBuffer;
83
84 if(x < 0)
85 LastMouseX = 0;
86 else
87 if(x > (int)VarInfo.xres - CURSOR_WIDTH)
88 LastMouseX = VarInfo.xres - CURSOR_WIDTH;
89 else
90 LastMouseX = x;
91
92 if(y < 0)
93 LastMouseY = 0;
94 else
95 if(y > (int)VarInfo.yres - CURSOR_HEIGHT)
96 LastMouseY = VarInfo.yres - CURSOR_HEIGHT;
97 else
98 LastMouseY = y;
99
100 bypp = VarInfo.bits_per_pixel / 8;
101 off = LastMouseY * FixedInfo.line_length + LastMouseX * bypp;
102 stride = CURSOR_WIDTH * bypp;
103 for(i = 0; i<CURSOR_HEIGHT; i++) {
104 memcpy(src, BackBuffer + off, stride);
105 src += stride;
106 off += FixedInfo.line_length;
107 }
108 }
109
110 void DrawCursor(void)
111 {
112 int i, j, px, py, xoff, xlen, yoff, ylen, bypp, cstride, dstride;
113 unsigned char *c;
114 const unsigned char *d;
115
116 if(!MouseVisible || CurrentCursor < 0 || CurrentCursor >= NUM_CURSORS)
117 return;
118
119 px = MouseX - CursorsXOffset[CurrentCursor];
120 py = MouseY - CursorsYOffset[CurrentCursor];
121
122 SaveCursor(px, py);
123
124 xoff = 0;
125 if(px < 0)
126 xoff = -px;
127
128 xlen = CURSOR_WIDTH;
129 if(px + CURSOR_WIDTH > VarInfo.xres)
130 xlen = VarInfo.xres - px;
131
132 yoff = 0;
133 if(py < 0)
134 yoff = -py;
135
136 ylen = CURSOR_HEIGHT;
137 if(py + CURSOR_HEIGHT > VarInfo.yres)
138 ylen = VarInfo.yres - py;
139
140 bypp = VarInfo.bits_per_pixel / 8;
141
142 c = BackBuffer + FixedInfo.line_length * (py + yoff) + (px + xoff) * bypp;
143 cstride = FixedInfo.line_length - bypp * (xlen - xoff);
144
145 d = Cursors[CurrentCursor] + (CURSOR_WIDTH * yoff + xoff)*4;
146 dstride = (CURSOR_WIDTH - xlen + xoff) * 4;
147
148 switch(bypp) {
149 case 1:
150 {
151 const int shift = 8 - REVERSECMAPSIZELOG;
152 for(i = yoff; i < ylen; i++) {
153 for(j = xoff; j < xlen; j++) {
154 if(d[3] < 220)
155 *c = ReverseColorMap
156 [(d[0]+(((int)(RedColorMap[c[0]]>>8)*d[3])>>8))>>shift]
157 [(d[1]+(((int)(GreenColorMap[c[0]]>>8)*d[3])>>8))>>shift]
158 [(d[2]+(((int)(BlueColorMap[c[0]]>>8)*d[3])>>8))>>shift];
159 c++;
160 d+=4;
161 }
162 d += dstride;
163 c += cstride;
164 }
165 } break;
166 case 2:
167 {
168 uint16_t *e = (void*)c;
169 cstride /= 2;
170 for(i = yoff; i < ylen; i++) {
171 for(j = xoff; j < xlen; j++) {
172 if(d[3] < 220)
173 e[0] = ((((d[0] + (((int)(((e[0] >> 8) & 0xf8)
174 | ((c[0] >> 11) & 0x7)) * d[3]) >> 8)) & 0xf8) << 8)
175 | (((d[1] + (((int)(((e[0] >> 3) & 0xfc)
176 | ((e[0] >> 5) & 0x3)) * d[3]) >> 8)) & 0xfc) << 3)
177 | ((d[2] + (((int)(((e[0] << 3) & 0xf8)
178 | (e[0] & 0x7)) * d[3]) >> 8)) >> 3));
179
180 e++;
181 d+=4;
182 }
183 d += dstride;
184 e += cstride;
185 }
186 } break;
187 case 3:
188 case 4:
189 for(i = yoff; i < ylen; i++) {
190 for(j = xoff; j < xlen; j++) {
191 if(d[3] < 220) {
192 c[0] = d[0] + (((int)c[0] * d[3]) >> 8);
193 c[1] = d[1] + (((int)c[1] * d[3]) >> 8);
194 c[2] = d[2] + (((int)c[2] * d[3]) >> 8);
195 }
196
197 c+=bypp;
198 d+=4;
199 }
200 d += dstride;
201 c += cstride;
202 } break;
203 }
204 }
205
206 #define MIN(x, y) x < y ? x : y
207 void SwapCursor(void)
208 {
209 int px = MouseX - CursorsXOffset[CurrentCursor];
210 int py = MouseY - CursorsYOffset[CurrentCursor];
211
212 int minx = MIN(px, LastMouseX);
213 int sizex = abs(px - LastMouseX);
214
215 int miny = MIN(py, LastMouseY);
216 int sizey = abs(py - LastMouseY);
217
218 if(MouseVisible)
219 DrawCursor();
220
221 /* now update the portion of the screen that has changed, this is also
222 used to hide the mouse if MouseVisible is 0 */
223 if(DisplayMode & GLUT_DOUBLE && ((sizex || sizey) || !MouseVisible)) {
224 int off, stride, i;
225 if(minx < 0)
226 minx = 0;
227 if(miny < 0)
228 miny = 0;
229
230 if(minx + sizex > VarInfo.xres - CURSOR_WIDTH)
231 sizex = VarInfo.xres - CURSOR_WIDTH - minx;
232 if(miny + sizey > VarInfo.yres - CURSOR_HEIGHT)
233 sizey = VarInfo.yres - CURSOR_HEIGHT - miny;
234 off = FixedInfo.line_length * miny
235 + minx * VarInfo.bits_per_pixel / 8;
236 stride = (sizex + CURSOR_WIDTH) * VarInfo.bits_per_pixel / 8;
237
238 for(i = 0; i < sizey + CURSOR_HEIGHT; i++) {
239 memcpy(FrameBuffer+off, BackBuffer+off, stride);
240 off += FixedInfo.line_length;
241 }
242 }
243 }
244
245 void glutWarpPointer(int x, int y)
246 {
247 if(x < 0)
248 x = 0;
249 if(x >= VarInfo.xres)
250 x = VarInfo.xres - 1;
251 MouseX = x;
252
253 if(y < 0)
254 y = 0;
255 if(y >= VarInfo.yres)
256 y = VarInfo.yres - 1;
257 MouseY = y;
258
259 EraseCursor();
260 SwapCursor();
261 }
262
263 void glutSetCursor(int cursor)
264 {
265 if(cursor == GLUT_CURSOR_FULL_CROSSHAIR)
266 cursor = GLUT_CURSOR_CROSSHAIR;
267
268 EraseCursor();
269 MouseVisible = 1;
270 CurrentCursor = cursor;
271 SwapCursor();
272 }