1 /* xscreensaver, Copyright (c) 1991-2018 Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
14 But it's a bunch of function definitions that bear some resemblance to
15 Xlib and that do things to an XImage that bear some resemblance to the
16 things that Xlib might have done.
18 This handles things when jwxyz-gl.c can't.
25 #ifdef JWXYZ_IMAGE /* entire file */
29 #include "jwxyz-timers.h"
35 union color_bytes { // Hello, again.
40 struct jwxyz_Display {
41 const struct jwxyz_vtbl *vtbl; // Must come first.
45 struct jwxyz_sources_data *timers_data;
47 unsigned long window_background;
56 extern const struct jwxyz_vtbl image_vtbl;
59 jwxyz_image_make_display (Window w, const unsigned char *rgba_bytes)
61 Display *d = (Display *) calloc (1, sizeof(*d));
62 d->vtbl = &image_vtbl;
64 Visual *v = &d->visual;
66 Assert (rgba_bytes[3] == 3, "alpha not last");
67 for (unsigned i = 0; i != 4; ++i) {
68 union color_bytes color;
70 color.bytes[rgba_bytes[i]] = 0xff;
71 v->rgba_masks[i] = color.pixel;
74 d->timers_data = jwxyz_sources_init (XtDisplayToApplicationContext (d));
75 d->window_background = BlackPixel(d,0);
82 jwxyz_image_free_display (Display *dpy)
84 jwxyz_sources_free (dpy->timers_data);
90 static jwxyz_sources_data *
91 display_sources_data (Display *dpy)
93 return dpy->timers_data;
100 return dpy->main_window;
104 visual (Display *dpy)
111 next_point(short *v, XPoint p, int mode)
114 case CoordModeOrigin:
118 case CoordModePrevious:
123 Assert (False, "next_point: bad mode");
128 #define SEEK_DRAWABLE(d, x, y) \
129 SEEK_XY (jwxyz_image_data(d), jwxyz_image_pitch(d), x, y)
132 DrawPoints (Display *dpy, Drawable d, GC gc,
133 XPoint *points, int count, int mode)
135 Assert (gc->gcv.function == GXcopy, "XDrawPoints: bad GC function");
137 const XRectangle *frame = jwxyz_frame (d);
139 for (unsigned i = 0; i < count; i++) {
140 next_point(v, points[i], mode);
141 if (v[0] >= 0 && v[0] < frame->width &&
142 v[1] >= 0 && v[1] < frame->height)
143 *SEEK_DRAWABLE(d, v[0], v[1]) = gc->gcv.foreground;
151 copy_area (Display *dpy, Drawable src, Drawable dst, GC gc,
152 int src_x, int src_y, unsigned int width, unsigned int height,
153 int dst_x, int dst_y)
155 jwxyz_blit (jwxyz_image_data (src), jwxyz_image_pitch (src), src_x, src_y,
156 jwxyz_image_data (dst), jwxyz_image_pitch (dst), dst_x, dst_y,
162 draw_line (Drawable d, unsigned long pixel,
163 short x0, short y0, short x1, short y1)
165 // TODO: Assert line_Width == 1, line_stipple == solid, etc.
167 const XRectangle *frame = jwxyz_frame (d);
168 if (x0 < 0 || x0 >= frame->width ||
169 x1 < 0 || x1 >= frame->width ||
170 y0 < 0 || y0 >= frame->height ||
171 y1 < 0 || y1 >= frame->height) {
172 Log ("draw_line: out of bounds");
176 int dx = abs(x1 - x0), dy = abs(y1 - y0);
178 unsigned dmod0, dmod1;
183 dpx0 = x1 > x0 ? 1 : -1;
184 dpx1 = y1 > y0 ? frame->width : -frame->width;
188 dpx0 = y1 > y0 ? frame->width : -frame->width;
189 dpx1 = x1 > x0 ? 1 : -1;
199 uint32_t *px = SEEK_DRAWABLE(d, x0, y0);
215 DrawLines (Display *dpy, Drawable d, GC gc, XPoint *points, int count,
218 short v[2] = {0, 0}, v_prev[2] = {0, 0};
219 unsigned long pixel = gc->gcv.foreground;
220 for (unsigned i = 0; i != count; ++i) {
221 next_point(v, points[i], mode);
223 draw_line (d, pixel, v_prev[0], v_prev[1], v[0], v[1]);
232 DrawSegments (Display *dpy, Drawable d, GC gc, XSegment *segments, int count)
234 unsigned long pixel = gc->gcv.foreground;
235 for (unsigned i = 0; i != count; ++i) {
236 XSegment *seg = &segments[i];
237 draw_line (d, pixel, seg->x1, seg->y1, seg->x2, seg->y2);
244 ClearWindow (Display *dpy, Window win)
246 Assert (win == dpy->main_window, "not a window");
247 const XRectangle *wr = jwxyz_frame (win);
248 return XClearArea (dpy, win, 0, 0, wr->width, wr->height, 0);
251 static unsigned long *
252 window_background (Display *dpy)
254 return &dpy->window_background;
258 fill_rects (Display *dpy, Drawable d, GC gc,
259 const XRectangle *rectangles, unsigned long nrectangles,
262 Assert (!gc || gc->gcv.function == GXcopy, "XDrawPoints: bad GC function");
264 const XRectangle *frame = jwxyz_frame (d);
265 void *image_data = jwxyz_image_data (d);
266 ptrdiff_t image_pitch = jwxyz_image_pitch (d);
268 for (unsigned i = 0; i != nrectangles; ++i) {
269 const XRectangle *rect = &rectangles[i];
270 unsigned x0 = rect->x >= 0 ? rect->x : 0, y0 = rect->y >= 0 ? rect->y : 0;
271 int x1 = rect->x + rect->width, y1 = rect->y + rect->height;
272 if (y1 > frame->height)
274 if (x1 > frame->width)
276 unsigned x_size = x1 - x0, y_size = y1 - y0;
277 void *dst = SEEK_XY (image_data, image_pitch, x0, y0);
279 # if __SIZEOF_WCHAR_T__ == 4
280 wmemset (dst, (wchar_t) pixel, x_size);
282 for(size_t i = 0; i != x_size; ++i)
283 ((uint32_t *)dst)[i] = pixel;
286 dst = (char *) dst + image_pitch;
293 FillPolygon (Display *dpy, Drawable d, GC gc,
294 XPoint *points, int npoints, int shape, int mode)
296 Log ("XFillPolygon: not implemented");
301 draw_arc (Display *dpy, Drawable d, GC gc, int x, int y,
302 unsigned int width, unsigned int height,
303 int angle1, int angle2, Bool fill_p)
305 Log ("jwxyz_draw_arc: not implemented");
325 CreateGC (Display *dpy, Drawable d, unsigned long mask, XGCValues *xgcv)
327 struct jwxyz_GC *gc = (struct jwxyz_GC *) calloc (1, sizeof(*gc));
328 gc->depth = jwxyz_drawable_depth (d);
330 jwxyz_gcv_defaults (dpy, &gc->gcv, gc->depth);
331 XChangeGC (dpy, gc, mask, xgcv);
337 FreeGC (Display *dpy, GC gc)
340 XUnloadFont (dpy, gc->gcv.font);
348 PutImage (Display *dpy, Drawable d, GC gc, XImage *ximage,
349 int src_x, int src_y, int dest_x, int dest_y,
350 unsigned int w, unsigned int h)
352 const XRectangle *wr = jwxyz_frame (d);
354 Assert (gc, "no GC");
355 Assert ((w < 65535), "improbably large width");
356 Assert ((h < 65535), "improbably large height");
357 Assert ((src_x < 65535 && src_x > -65535), "improbably large src_x");
358 Assert ((src_y < 65535 && src_y > -65535), "improbably large src_y");
359 Assert ((dest_x < 65535 && dest_x > -65535), "improbably large dest_x");
360 Assert ((dest_y < 65535 && dest_y > -65535), "improbably large dest_y");
362 // Clip width and height to the bounds of the Drawable
364 if (dest_x + w > wr->width) {
365 if (dest_x > wr->width)
367 w = wr->width - dest_x;
369 if (dest_y + h > wr->height) {
370 if (dest_y > wr->height)
372 h = wr->height - dest_y;
374 if (w <= 0 || h <= 0)
377 // Clip width and height to the bounds of the XImage
379 if (src_x + w > ximage->width) {
380 if (src_x > ximage->width)
382 w = ximage->width - src_x;
384 if (src_y + h > ximage->height) {
385 if (src_y > ximage->height)
387 h = ximage->height - src_y;
389 if (w <= 0 || h <= 0)
394 if (jwxyz_dumb_drawing_mode(dpy, d, gc, dest_x, dest_y, w, h))
397 XGCValues *gcv = gc_gcv (gc);
399 Assert (gcv->function == GXcopy, "XPutImage: bad GC function");
400 Assert (!ximage->xoffset, "XPutImage: bad xoffset");
403 src_pitch = ximage->bytes_per_line,
404 dst_pitch = jwxyz_image_pitch (d);
406 const void *src_ptr = SEEK_XY (ximage->data, src_pitch, src_x, src_y);
407 void *dst_ptr = SEEK_XY (jwxyz_image_data (d), dst_pitch, dest_x, dest_y);
409 if (gcv->alpha_allowed_p) {
410 Assert (ximage->depth == 32, "XPutImage: depth != 32");
411 Assert (ximage->format == ZPixmap, "XPutImage: bad format");
412 Assert (ximage->bits_per_pixel == 32, "XPutImage: bad bits_per_pixel");
414 const uint8_t *src_row = src_ptr;
415 uint8_t *dst_row = dst_ptr;
417 /* Slight loss of precision here: color values may end up being one less
418 than what they should be.
421 for (unsigned x = 0; x != w; ++x) {
422 // Pixmaps don't contain alpha. (Yay.)
423 const uint8_t *src = src_row + x * 4;
424 uint8_t *dst = dst_row + x * 4;
426 // ####: This is pretty SIMD friendly.
427 // Protip: Align dst (load + store), let src be unaligned (load only)
428 uint16_t alpha = src[3], alpha1 = 0xff - src[3];
429 dst[0] = (src[0] * alpha + dst[0] * alpha1) >> 8;
430 dst[1] = (src[1] * alpha + dst[1] * alpha1) >> 8;
431 dst[2] = (src[2] * alpha + dst[2] * alpha1) >> 8;
434 src_row += src_pitch;
435 dst_row += dst_pitch;
439 Assert (ximage->depth == 1 || ximage->depth == 32,
440 "XPutImage: depth != 1 && depth != 32");
442 if (ximage->depth == 32) {
443 Assert (ximage->format == ZPixmap, "XPutImage: bad format");
444 Assert (ximage->bits_per_pixel == 32, "XPutImage: bad bits_per_pixel");
445 jwxyz_blit (ximage->data, ximage->bytes_per_line, src_x, src_y,
446 jwxyz_image_data (d), jwxyz_image_pitch (d), dest_x, dest_y,
449 Log ("XPutImage: depth == 1");
457 GetSubImage (Display *dpy, Drawable d, int x, int y,
458 unsigned int width, unsigned int height,
459 unsigned long plane_mask, int format,
460 XImage *dest_image, int dest_x, int dest_y)
462 Assert ((width < 65535), "improbably large width");
463 Assert ((height < 65535), "improbably large height");
464 Assert ((x < 65535 && x > -65535), "improbably large x");
465 Assert ((y < 65535 && y > -65535), "improbably large y");
467 Assert (dest_image->depth == 32 && jwxyz_drawable_depth (d) == 32,
468 "XGetSubImage: bad depth");
469 Assert (format == ZPixmap, "XGetSubImage: bad format");
471 jwxyz_blit (jwxyz_image_data (d), jwxyz_image_pitch (d), x, y,
472 dest_image->data, dest_image->bytes_per_line, dest_x, dest_y,
480 SetClipMask (Display *dpy, GC gc, Pixmap m)
482 Log ("TODO: No clip masks yet"); // Slip/colorbars.c needs this.
487 SetClipOrigin (Display *dpy, GC gc, int x, int y)
489 gc->gcv.clip_x_origin = x;
490 gc->gcv.clip_y_origin = y;
495 const struct jwxyz_vtbl image_vtbl = {
498 display_sources_data,
522 #endif /* JWXYZ_IMAGE -- entire file */