1 
2 /*
3  *  Diverse Bristol audio routines.
4  *  Copyright (c) by Nick Copeland <nickycopeland@hotmail.com> 1996,2012
5  *
6  *
7  *   This program is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU General Public License as published by
9  *   the Free Software Foundation; either version 3 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program; if not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #include "brightonX11internals.h"
23 
24 /*
25  * At the moment (14/3/02) this code uses XDrawPoint directly onto the screen.
26  * It could be accelerated by using an XImage structure. In the mean time this
27  * will be accelerated using XDrawPoints() rather than the singular version.
28  */
29 int
BCopyArea(brightonDisplay * display,int x,int y,int w,int h,int dx,int dy)30 BCopyArea(brightonDisplay *display, int x, int y, int w, int h, int dx, int dy)
31 {
32 	bdisplay *bd = display->display;
33 
34 /*printf("BCopyArea(%x %x, (%i/%i/%i/%i) (%i/%i/%i,%i) %x\n",*/
35 /*bd, display->image, x, y, w, h, dx, dy, bd->width, bd->height, bd->gc);*/
36 
37 	if ((display->image == NULL) || (display->flags & _BRIGHTON_WINDOW))
38 		return(0);
39 
40 #ifdef BRIGHTON_XIMAGE
41 	/* 0.10.7 code for XImage accelerators */
42 	if (display->flags & BRIGHTON_BIMAGE)
43 	{
44 //printf("image copy code %i %i, %i %i, %i %i\n", x, y, dx, dy, w, h);
45 #ifdef BRIGHTON_SHMIMAGE
46 		XShmPutImage(bd->display,
47 			(Window) ((brightonWindow *) display->bwin)->win,
48 			(GC) ((brightonWindow *) display->bwin)->gc,
49 			(XImage *) display->image,
50 				x, y, dx, dy, w, h, False);
51 #else
52 		XPutImage(bd->display, (Window) ((brightonWindow *) display->bwin)->win,
53 			(GC) ((brightonWindow *) display->bwin)->gc,
54 			(XImage *) display->image,
55 				x, y, dx, dy, w, h);
56 #endif
57 	} else
58 #endif
59 		XCopyArea(bd->display, (Pixmap) display->image,
60 			(Window) ((brightonWindow *) display->bwin)->win,
61 			(GC) ((brightonWindow *) display->bwin)->gc,
62 				x, y, w, h, dx, dy);
63 
64 	return(0);
65 }
66 
67 int
BResizeWindow(brightonDisplay * display,brightonWindow * bwin,int width,int height)68 BResizeWindow(brightonDisplay *display, brightonWindow *bwin,
69 int width, int height)
70 {
71 	bdisplay *bd = display->display;
72 
73 /*printf("BResizeWindow(%x, %x, %i, %i)\n", display, bwin, width, height);*/
74 
75 	if (~display->flags & _BRIGHTON_WINDOW)
76 		XResizeWindow(bd->display, (Window) bwin->win, width, height);
77 
78 	return(0);
79 }
80 
81 #ifdef BRIGHTON_XIMAGE
82 #ifdef BRIGHTON_SHMIMAGE
83 static int
BDrawImage(brightonDisplay * display,brightonBitmap * bitmap,int sx,int sy,int sw,int sh,int destx,int desty)84 BDrawImage(brightonDisplay *display, brightonBitmap *bitmap,
85 int sx, int sy, int sw, int sh,
86 int destx, int desty)
87 {
88 	register bdisplay *bd = display->display;
89 /*	register brightonWindow *bwin = (brightonWindow *) display->bwin; */
90 	register brightonPalette *palette = display->palette;
91 	register int *pixels = bitmap->pixels;
92 	register int x, y, pindex;
93 	register int dx, dy = desty;
94 	XImage *image;
95 	struct shmid_ds myshmid;
96 
97 //printf("BDrawImage(%p, (%i/%i/%i/%i) (%i/%i) (%i/%i) %i\n",
98 //bitmap, sx, sy, sw, sh, destx, desty, bd->width, bd->height, bd->depth);
99 
100 	if (display->flags & _BRIGHTON_WINDOW)
101 		return(0);
102 
103 	/*
104 	 * See if we need an image or to resize the image
105 	 */
106 	if (display->image == 0)
107 	{
108 		char *iData;
109 		Visual *visual = DefaultVisual(bd->display, bd->screen_num);
110 
111 		bd->width = ((brightonWindow *) display->bwin)->width;
112 		bd->height = ((brightonWindow *) display->bwin)->height;
113 
114 		iData = brightonX11malloc(bd->width * bd->height * sizeof(unsigned));
115 
116 		/*
117 		 * The bitmap pad has several interpretations and none of them seem
118 		 * consistent, however if the last two parameters are not correctly
119 		 * given then the call fails (seen on 64bit systems). We did have:
120 		 *
121 		 *	8 * sizeof(long) - bd->depth, sizeof(long) * bd->width))
122 		 *
123 		 * This had been changed to
124 		 *
125 		 *	bd->depth >= 24? 32: bd->depth, 0
126 		 *
127 		 * However correctly speaking we might prefer
128 		 *
129 		 *	bd->depth > 16? 32: bd->depth > 8? 16:8, 0
130 		 */
131 		if ((image = (void *)
132 			XShmCreateImage(
133 				bd->display,
134 				visual,
135 				bd->depth,
136 				ZPixmap,
137 				0,
138 				&bd->shminfo,
139 				bd->width, bd->height))
140 			== NULL)
141 		{
142 			printf("failed to allocate image: try using option -pixmap\n");
143 			brightonX11free(iData);
144 			return(0);
145 		}
146 		/* Get the shared memory and check for errors */
147 		bd->shminfo.shmid = shmget(IPC_PRIVATE,
148 			image->bytes_per_line * image->height,
149 			IPC_CREAT | 0777 );
150 
151 		if(bd->shminfo.shmid < 0)
152 			return(0);
153 		/* attach, and check for errrors */
154 		bd->shminfo.shmaddr = image->data =
155 			(char *) shmat(bd->shminfo.shmid, 0, 0);
156 		if (bd->shminfo.shmaddr == (char *) -1)
157 			return 1;
158 		/* set as read/write, and attach to the display */
159 		bd->shminfo.readOnly = False;
160 		XShmAttach(bd->display, &bd->shminfo);
161 
162 		/*
163 		 * This looks odd but now that we have attached it, mark it for
164 		 * deletion. This will clear up the mess after all the detaches
165 		 * have occured.
166 		 */
167 		shmctl(bd->shminfo.shmid, IPC_STAT, &myshmid);
168 		shmctl(bd->shminfo.shmid, IPC_RMID, &myshmid);
169 
170 		display->image = (void *) image;
171 	} else if ((bd->width != ((brightonWindow *) display->bwin)->width)
172 			|| (bd->height != ((brightonWindow *) display->bwin)->height))
173 	{
174 		char *iData;
175 		Visual *visual = DefaultVisual(bd->display, bd->screen_num);
176 
177 		XShmDetach(bd->display, &bd->shminfo);
178 		XDestroyImage((XImage *) display->image);
179 		shmdt(bd->shminfo.shmaddr);
180 
181 		bd->width = ((brightonWindow *) display->bwin)->width;
182 		bd->height = ((brightonWindow *) display->bwin)->height;
183 
184 		iData = brightonX11malloc(bd->width * bd->height * sizeof(unsigned));
185 
186 		if ((image = (void *)
187 			XShmCreateImage(
188 				bd->display,
189 				visual,
190 				bd->depth,
191 				ZPixmap,
192 				0,
193 				&bd->shminfo,
194 				bd->width, bd->height))
195 			== NULL)
196 		{
197 			printf("failed to reallocate image\n");
198 			brightonX11free(iData);
199 			return(0);
200 		}
201 		/* Get the shared memory and check for errors */
202 		bd->shminfo.shmid = shmget(IPC_PRIVATE,
203 			image->bytes_per_line * image->height,
204 			IPC_CREAT | 0777 );
205 		if(bd->shminfo.shmid < 0)
206 			return(0);
207 		/* attach, and check for errrors */
208 		bd->shminfo.shmaddr = image->data =
209 			(char *) shmat(bd->shminfo.shmid, 0, 0);
210 		if (bd->shminfo.shmaddr == (char *) -1)
211 			return 1;
212 		/* set as read/write, and attach to the display */
213 		bd->shminfo.readOnly = False;
214 		XShmAttach(bd->display, &bd->shminfo);
215 
216 		/*
217 		 * This looks odd but now that we have attached it, mark it for
218 		 * deletion. This will clear up the mess after all the detaches
219 		 * have occured.
220 		 */
221 		shmctl(bd->shminfo.shmid, IPC_STAT, &myshmid);
222 		shmctl(bd->shminfo.shmid, IPC_RMID, &myshmid);
223 
224 		display->image = (void *) image;
225 	}
226 
227 	/*
228 	 * We now go through each pixel in the bitmap, check we have its color, and
229 	 * then render it onto the pixmap. After that we copy the relevant area
230 	 * of the pixmap over to the screen.
231 	 *
232 	 * This is currently the main performance hog since the color cache was
233 	 * implemented in the libbrighton color management code. The only real
234 	 * resolution that I can see is to use on screen bitmap management.
235 	 */
236 	for (y = sy; y < (sy + sh); y++)
237 	{
238 		if (y >= bitmap->height)
239 			break;
240 
241 		dx = destx;
242 
243 		for (x = sx; x < (sx + sw); x++)
244 		{
245 			if (x >= bitmap->width)
246 				break;
247 
248 			pindex = y * bitmap->width + x;
249 
250 			/*
251 			 * Do not render blue
252 			 */
253 			if ((palette[pixels[pindex]].red == 0)
254 				&& (palette[pixels[pindex]].green == 0)
255 				&& (palette[pixels[pindex]].blue == 65535))
256 			{
257 				++dx;
258 				continue;
259 			}
260 
261 			if (palette[pixels[pindex]].pixel < 0)
262 			{
263 				/*
264 				 * Allocate a color so we can start painting with them.
265 				 */
266 				BAllocColor(display, &palette[pixels[pindex]],
267 					palette[pixels[pindex]].red,
268 					palette[pixels[pindex]].green,
269 					palette[pixels[pindex]].blue);
270 			}
271 
272 			XPutPixel((XImage *) display->image,
273 				dx, dy, palette[pixels[pindex]].pixel);
274 
275 			++dx;
276 		}
277 
278 		++dy;
279 	}
280 
281 	BCopyArea(display, destx, desty, sw, sh, destx, desty);
282 
283 	return(0);
284 }
285 #else /* ShmImage code */
286 static int
BDrawImage(brightonDisplay * display,brightonBitmap * bitmap,int sx,int sy,int sw,int sh,int destx,int desty)287 BDrawImage(brightonDisplay *display, brightonBitmap *bitmap,
288 int sx, int sy, int sw, int sh,
289 int destx, int desty)
290 {
291 	register bdisplay *bd = display->display;
292 /*	register brightonWindow *bwin = (brightonWindow *) display->bwin; */
293 	register brightonPalette *palette = display->palette;
294 	register int *pixels = bitmap->pixels;
295 	register int x, y, pindex;
296 	register int dx, dy = desty;
297 
298 //printf("BDrawImage(%x %x, (%i/%i/%i/%i) (%i/%i) (%i/%i) %i\n",
299 //bwin, bitmap, sx, sy, sw, sh, destx, desty, bd->width, bd->height, bd->depth);
300 	if (display->flags & _BRIGHTON_WINDOW)
301 		return(0);
302 
303 	/*
304 	 * See if we need an image or to resize the image
305 	 */
306 	if (display->image == 0)
307 	{
308 		char *iData;
309 		Visual *visual = DefaultVisual(bd->display, bd->screen_num);
310 
311 		bd->width = ((brightonWindow *) display->bwin)->width;
312 		bd->height = ((brightonWindow *) display->bwin)->height;
313 
314 		iData = brightonX11malloc(bd->width * bd->height * sizeof(unsigned));
315 
316 		/*
317 		 * The bitmap pad has several interpretations and none of them seem
318 		 * consistent, however if the last two parameters are not correctly
319 		 * given then the call fails (seen on 64bit systems). We did have:
320 		 *
321 		 *	8 * sizeof(long) - bd->depth, sizeof(long) * bd->width))
322 		 *
323 		 * This had been changed to
324 		 *
325 		 *	bd->depth >= 24? 32: bd->depth, 0
326 		 *
327 		 * However correctly speaking we might prefer
328 		 *
329 		 *	bd->depth > 16? 32: bd->depth > 8? 16:8, 0
330 		 */
331 		if ((display->image = (void *)
332 			XCreateImage(
333 				bd->display,
334 				visual,
335 				bd->depth,
336 				ZPixmap,
337 				0,
338 				iData,
339 				bd->width, bd->height,
340 		 		bd->depth > 16? 32:bd->depth > 8? 16:8,
341 				0))
342 			== NULL)
343 		{
344 			printf("failed to allocate image: try using option -pixmap\n");
345 			brightonX11free(iData);
346 			return(0);
347 		}
348 	} else if ((bd->width != ((brightonWindow *) display->bwin)->width)
349 			|| (bd->height != ((brightonWindow *) display->bwin)->height))
350 	{
351 		char *iData;
352 		Visual *visual = DefaultVisual(bd->display, bd->screen_num);
353 
354 		XDestroyImage((XImage *) display->image);
355 
356 		bd->width = ((brightonWindow *) display->bwin)->width;
357 		bd->height = ((brightonWindow *) display->bwin)->height;
358 
359 		iData = brightonX11malloc(bd->width * bd->height * sizeof(unsigned));
360 
361 		if ((display->image = (void *)
362 			XCreateImage(
363 				bd->display,
364 				visual,
365 				bd->depth,
366 				ZPixmap,
367 				0,
368 				iData,
369 				bd->width, bd->height,
370 		 		bd->depth > 16? 32:bd->depth > 8? 16:8,
371 				0))
372 			== NULL)
373 		{
374 			printf("failed to reallocate image\n");
375 			brightonX11free(iData);
376 			return(0);
377 		}
378 	}
379 
380 	/*
381 	 * We now go through each pixel in the bitmap, check we have its color, and
382 	 * then render it onto the pixmap. After that we copy the relevant area
383 	 * of the pixmap over to the screen.
384 	 *
385 	 * This is currently the main performance hog since the color cache was
386 	 * implemented in the libbrighton color management code. The only real
387 	 * resolution that I can see is to use on screen bitmap management.
388 	 */
389 	for (y = sy; y < (sy + sh); y++)
390 	{
391 		if (y >= bitmap->height)
392 			break;
393 
394 		dx = destx;
395 
396 		for (x = sx; x < (sx + sw); x++)
397 		{
398 			if (x >= bitmap->width)
399 				break;
400 
401 			pindex = y * bitmap->width + x;
402 
403 			/*
404 			 * Do not render blue
405 			 */
406 			if ((palette[pixels[pindex]].red == 0)
407 				&& (palette[pixels[pindex]].green == 0)
408 				&& (palette[pixels[pindex]].blue == 65535))
409 			{
410 				++dx;
411 				continue;
412 			}
413 
414 			if (palette[pixels[pindex]].pixel < 0)
415 			{
416 				/*
417 				 * Allocate a color so we can start painting with them.
418 				 */
419 				BAllocColor(display, &palette[pixels[pindex]],
420 					palette[pixels[pindex]].red,
421 					palette[pixels[pindex]].green,
422 					palette[pixels[pindex]].blue);
423 			}
424 
425 			XPutPixel((XImage *) display->image,
426 				dx, dy, palette[pixels[pindex]].pixel);
427 
428 			++dx;
429 		}
430 
431 		++dy;
432 	}
433 
434 	BCopyArea(display, destx, desty, sw, sh, destx, desty);
435 
436 	return(0);
437 }
438 #endif /* note shmImage code */
439 #endif /* Image code */
440 
441 static int
BDrawPixmap(brightonDisplay * display,brightonBitmap * bitmap,int sx,int sy,int sw,int sh,int destx,int desty)442 BDrawPixmap(brightonDisplay *display, brightonBitmap *bitmap,
443 int sx, int sy, int sw, int sh,
444 int destx, int desty)
445 {
446 	bdisplay *bd = display->display;
447 	brightonWindow *bwin = (brightonWindow *) display->bwin;
448 	brightonQRender *qrender = bd->qrender;
449 	brightonPalette *palette = display->palette;
450 	int *pixels = bitmap->pixels, ncolors = bd->ocount, cindex;
451 	int missed = 0;
452 	GC tgc;
453 	int x, y, pindex;
454 	int dx, dy = desty;
455 
456 /*printf("BDrawArea(%x %x, (%i/%i/%i/%i) (%i/%i) (%i/%i) %i\n",*/
457 /*bwin, bitmap, sx, sy, sw, sh, destx, desty, bd->width, bd->height, bd->depth);*/
458 
459 	if (display->flags & _BRIGHTON_WINDOW)
460 		return(0);
461 
462 	if (qrender == 0)
463 	{
464 		qrender = (brightonQRender *)
465 			brightonX11malloc(BRIGHTON_QR_COLORS * sizeof(brightonQRender));
466 		bd->qrender = qrender;
467 		ncolors = bd->ocount = BRIGHTON_QR_COLORS;
468 	}
469 
470 	/*
471 	 * See if we need an image or to resize the image
472 	 */
473 	if (display->image == 0)
474 	{
475 		bd->width = ((brightonWindow *) display->bwin)->width;
476 		bd->height = ((brightonWindow *) display->bwin)->height;
477 
478 		display->image = (void *) XCreatePixmap(bd->display, (Window) bwin->win,
479 			bd->width, bd->height, bd->depth);
480 	} else {
481 		if ((bd->width != ((brightonWindow *) display->bwin)->width)
482 			|| (bd->height != ((brightonWindow *) display->bwin)->height))
483 		{
484 			XFreePixmap(bd->display, (Pixmap) display->image);
485 
486 			bd->width = ((brightonWindow *) display->bwin)->width;
487 			bd->height = ((brightonWindow *) display->bwin)->height;
488 
489 			display->image = (void *) XCreatePixmap(bd->display,
490 				(Window) bwin->win, bd->width, bd->height, bd->depth);
491 		}
492 	}
493 
494 	/*
495 	 * We now go through each pixel in the bitmap, check we have its color, and
496 	 * then render it onto the pixmap. After that we copy the relevant area
497 	 * of the pixmap over to the screen.
498 	 *
499 	 * This is currently the main performance hog since the color cache was
500 	 * implemented in the libbrighton color management code. The only real
501 	 * resolution that I can see is to use on screen bitmap management.
502 	 */
503 	for (y = sy; y < (sy + sh); y++)
504 	{
505 		if (y >= bitmap->height)
506 			break;
507 
508 		dx = destx;
509 
510 		for (x = sx; x < (sx + sw); x++)
511 		{
512 			if (x >= bitmap->width)
513 				break;
514 
515 			pindex = y * bitmap->width + x;
516 
517 			/*
518 			 * Do not render blue
519 			 */
520 			if ((palette[pixels[pindex]].red == 0)
521 				&& (palette[pixels[pindex]].green == 0)
522 				&& (palette[pixels[pindex]].blue == 65535))
523 			{
524 				++dx;
525 				continue;
526 			}
527 
528 			if (palette[pixels[pindex]].gc == 0)
529 			{
530 				/*
531 				 * Get a GC
532 				 */
533 				BAllocGC(display, &palette[pixels[pindex]],
534 					palette[pixels[pindex]].red,
535 					palette[pixels[pindex]].green,
536 					palette[pixels[pindex]].blue);
537 			}
538 
539 			tgc = palette[pixels[pindex]].gc;
540 			for (cindex = 0; cindex < ncolors; cindex++)
541 			{
542 				if (qrender[cindex].gc == tgc)
543 					break;
544 
545 				if (qrender[cindex].gc == 0)
546 				{
547 					/*
548 					 * We have not filled this queue yet.
549 					 */
550 					qrender[cindex].gc = tgc;
551 					qrender[cindex].index = cindex;
552 					break;
553 				}
554 			}
555 
556 			if (cindex == ncolors) {
557 				missed++;
558 				XDrawPoint(bd->display, (Pixmap) display->image,
559 					(GC) palette[pixels[pindex]].gc, dx, dy);
560 			} else {
561 				qrender[cindex].queue[qrender[cindex].count].x = dx;
562 				qrender[cindex].queue[qrender[cindex].count].y = dy;
563 				if (++qrender[cindex].count == BRIGHTON_QR_QSIZE)
564 				{
565 					XDrawPoints(bd->display, (Pixmap) display->image,
566 						tgc, qrender[cindex].queue, BRIGHTON_QR_QSIZE,
567 						CoordModeOrigin);
568 					qrender[cindex].count = 0;
569 				}
570 			}
571 
572 			++dx;
573 		}
574 
575 		++dy;
576 	}
577 
578 	for (cindex = 0; cindex < ncolors; cindex++)
579 	{
580 		if (qrender[cindex].count == 0)
581 			continue;
582 
583 		XDrawPoints(bd->display, (Pixmap) display->image,
584 			qrender[cindex].gc, qrender[cindex].queue,
585 			qrender[cindex].count, CoordModeOrigin);
586 
587 		qrender[cindex].count = 0;
588 	}
589 
590 	if (missed)
591 	{
592 		brightonX11free(bd->qrender);
593 		bd->ocount += BRIGHTON_QR_COLORS;
594 
595 		bd->qrender = (brightonQRender *)
596 			brightonX11malloc(bd->ocount * sizeof(brightonQRender));
597 /*printf("Allocated %i colors (%i)\n", ncolors, bd->ocount);*/
598 	}
599 	BCopyArea(display, destx, desty, sw, sh, destx, desty);
600 
601 	return(0);
602 }
603 
604 int
BDrawArea(brightonDisplay * display,brightonBitmap * bitmap,int sx,int sy,int sw,int sh,int destx,int desty)605 BDrawArea(brightonDisplay *display, brightonBitmap *bitmap,
606 int sx, int sy, int sw, int sh, int destx, int desty)
607 {
608 	if (display->flags & _BRIGHTON_WINDOW)
609 		return(0);
610 
611 #ifdef BRIGHTON_XIMAGE
612 	/* 0.10.7 code for XImage accelerators */
613 	if (display->flags & BRIGHTON_BIMAGE)
614 		return(BDrawImage(display, bitmap, sx, sy, sw, sh, destx, desty));
615 #endif
616 
617 	return(BDrawPixmap(display, bitmap, sx, sy, sw, sh, destx, desty));
618 }
619