9bf2661e6982592ea1748c3373f2012da5e5271e
[xscreensaver] / jwxyz / jwxyz-gl.c
1 /* xscreensaver, Copyright (c) 1991-2018 Jamie Zawinski <jwz@jwz.org>
2  *
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 
9  * implied warranty.
10  */
11
12 /* JWXYZ Is Not Xlib.
13
14    But it's a bunch of function definitions that bear some resemblance to
15    Xlib and that do OpenGL-ish things that bear some resemblance to the
16    things that Xlib might have done.
17
18    This is the version of jwxyz for Android.  The version used by MacOS
19    and iOS is in jwxyz.m.
20  */
21
22 /* Be advised, this is all very much a work in progress. */
23
24 /* FWIW, at one point macOS 10.x could actually run with 256 colors. It might
25    not be able to do this anymore, though.
26  */
27
28 /* TODO:
29    - malloc error checking
30    - Check max texture sizes for XGet/PutImage, XCopyArea.
31    - Optional 5:5:5 16-bit color
32 */
33
34 /* Techniques & notes:
35    - iOS: OpenGL ES 2.0 isn't always available. Use OpenGL ES 1.1.
36    - OS X: Drivers can go back to OpenGL 1.1 (GeForce 2 MX on 10.5.8).
37    - Use stencil buffers (OpenGL 1.0+) for bitmap clipping masks.
38    - Pixmaps can be any of the following, depending on GL implementation.
39      - This requires offscreen rendering. Fortunately, this is always
40        available.
41        - OS X: Drawable objects, including: pixel buffers and offscreen
42          memory.
43          - Offscreen buffers w/ CGLSetOffScreen (10.0+)
44          - http://lists.apple.com/archives/mac-opengl/2002/Jun/msg00087.html
45            provides a very ugly solution for hardware-accelerated offscreen
46            rendering with CGLSetParameter(*, kCGLCPSurfaceTexture, *) on OS X
47            10.1+. Apple docs say it's actually for OS X 10.3+, instead.
48          - Pixel buffers w/ CGLSetPBuffer (10.3+, now deprecated)
49            - Requires APPLE_pixel_buffer.
50              - Available in software on x86 only.
51              - Always available on hardware.
52            - Need to blit? Use OpenGL pixel buffers. (GL_PIXEL_PACK_BUFFER)
53          - Framebuffer objects w/ GL_(ARB|EXT)_framebuffer_object
54            - TODO: Can EXT_framebuffers be different sizes?
55            - Preferred on 10.7+
56        - iOS: Use OES_framebuffer_object, it's always present.
57  */
58
59 /* OpenGL hacks call a number of X11 functions, including
60    XCopyArea, XDrawString, XGetImage
61    XCreatePixmap, XCreateGC, XCreateImage
62    XPutPixel
63    Check these, of course.
64  */
65
66 #ifdef JWXYZ_GL /* entire file */
67
68 #include <math.h>
69 #include <limits.h>
70 #include <stddef.h>
71 #include <stdlib.h>
72 #include <stdint.h>
73 #include <string.h>
74 #include <wchar.h>
75
76 #ifdef HAVE_COCOA
77 # ifdef USE_IPHONE
78 #  import <QuartzCore/QuartzCore.h>
79 #  include <OpenGLES/ES1/gl.h>
80 #  include <OpenGLES/ES1/glext.h>
81 # else
82 #  include <OpenGL/glu.h>
83 # endif
84 #else
85 /* TODO: Does this work on iOS? */
86 # ifndef HAVE_JWZGLES
87 #  include <gl/glu.h>
88 # else
89 #  include <GLES/gl.h>
90 #  include <GLES/glext.h>
91 # endif
92 #endif
93
94 #ifdef HAVE_JWZGLES
95 # include "jwzglesI.h"
96 #endif
97
98 #include "jwxyzI.h"
99 #include "jwxyz-timers.h"
100 #include "yarandom.h"
101 #include "utf8wc.h"
102 #include "xft.h"
103 #include "pow2.h"
104
105 #define countof(x) (sizeof((x))/sizeof((*x)))
106
107 union color_bytes {
108   uint32_t pixel;
109   uint8_t bytes[4];
110 };
111
112 // Use two textures: one for RGBA, one for luminance. Older Android doesn't
113 // seem to like it when textures change format.
114 enum {
115   texture_rgba,
116   texture_mono
117 };
118
119 struct jwxyz_Display {
120   const struct jwxyz_vtbl *vtbl; // Must come first.
121
122   Window main_window;
123   GLenum pixel_format, pixel_type;
124   Visual visual;
125   struct jwxyz_sources_data *timers_data;
126
127   Bool gl_texture_npot_p;
128   /* Bool opengl_core_p */;
129   GLenum gl_texture_target;
130   
131   GLuint textures[2]; // Also can work on the desktop.
132
133   unsigned long window_background;
134
135   int gc_function;
136   Bool gc_alpha_allowed_p;
137
138   // Alternately, there could be one queue per pixmap.
139   size_t queue_size, queue_capacity;
140   Drawable queue_drawable;
141   GLint queue_mode;
142   void *queue_vertex;
143   uint32_t *queue_color;
144   Bool queue_line_cap;
145 };
146
147 struct jwxyz_GC {
148   XGCValues gcv;
149   unsigned int depth;
150 };
151
152 struct jwxyz_linked_point {
153     short x, y;
154     linked_point *next;
155 };
156
157
158 void
159 jwxyz_assert_display(Display *dpy)
160 {
161   if(!dpy)
162     return;
163   jwxyz_assert_gl ();
164   jwxyz_assert_drawable (dpy->main_window, dpy->main_window);
165 }
166
167
168 void
169 jwxyz_set_matrices (Display *dpy, unsigned width, unsigned height,
170                     Bool window_p)
171 {
172   Assert (width, "no width");
173   Assert (height, "no height");
174
175   /* TODO: Check registration pattern from Interference with rectangles instead of points. */
176
177   // The projection matrix is always set as follows. The modelview matrix is
178   // usually identity, but for points and thin lines, it's translated by 0.5.
179   glMatrixMode(GL_PROJECTION);
180   glLoadIdentity();
181   
182 # if defined(USE_IPHONE) || defined(HAVE_ANDROID)
183
184   if (window_p && ignore_rotation_p(dpy)) {
185     int o = (int) current_device_rotation();
186     glRotatef (-o, 0, 0, 1);
187   }
188
189   // glPointSize(1); // This is the default.
190   
191 #ifdef HAVE_JWZGLES
192   glOrthof /* TODO: Is glOrthox worth it? Signs point to no. */
193 #else
194   glOrtho
195 #endif
196     (0, width, height, 0, -1, 1);
197
198   glMatrixMode(GL_MODELVIEW);
199 # endif // HAVE_MOBILE
200 }
201
202 #ifndef HAVE_JWZGLES
203
204 struct gl_version
205 {
206   // iOS always uses OpenGL ES 1.1.
207   unsigned major;
208   unsigned minor;
209 };
210
211 static GLboolean
212 gl_check_ver (const struct gl_version *caps,
213               unsigned gl_major,
214               unsigned gl_minor)
215 {
216   return caps->major > gl_major ||
217            (caps->major == gl_major && caps->minor >= gl_minor);
218 }
219
220 #endif
221
222
223 extern const struct jwxyz_vtbl gl_vtbl;
224
225 Display *
226 jwxyz_gl_make_display (Window w)
227 {
228   Display *d = (Display *) calloc (1, sizeof(*d));
229   d->vtbl = &gl_vtbl;
230
231 # ifndef HAVE_JWZGLES
232   struct gl_version version;
233
234   {
235     const GLubyte *version_str = glGetString (GL_VERSION);
236
237     /* iPhone is always OpenGL ES 1.1. */
238     if (sscanf ((const char *) version_str, "%u.%u",
239                 &version.major, &version.minor) < 2)
240     {
241       version.major = 1;
242       version.minor = 1;
243     }
244   }
245 # endif // !HAVE_JWZGLES
246
247   const GLubyte *extensions = glGetString (GL_EXTENSIONS);
248
249   /* See:
250      - Apple TN2080: Understanding and Detecting OpenGL Functionality.
251      - OpenGL Programming Guide for the Mac - Best Practices for Working with
252        Texture Data - Optimal Data Formats and Types
253    */
254
255   // If a video adapter suports BGRA textures, then that's probably as fast as
256   // you're gonna get for getting a texture onto the screen.
257 # ifdef HAVE_JWZGLES
258   /* TODO: Make BGRA work on iOS. As it is, it breaks XPutImage. (glTexImage2D, AFAIK) */
259   d->pixel_format = GL_RGBA; /*
260     gluCheckExtension ((const GLubyte *) "GL_APPLE_texture_format_BGRA8888",
261                        extensions) ? GL_BGRA_EXT : GL_RGBA; */
262   d->pixel_type = GL_UNSIGNED_BYTE;
263   // See also OES_read_format.
264 # else  // !HAVE_JWZGLES
265   if (gl_check_ver (&version, 1, 2) ||
266       (gluCheckExtension ((const GLubyte *) "GL_EXT_bgra", extensions) &&
267        gluCheckExtension ((const GLubyte *) "GL_APPLE_packed_pixels",
268                           extensions))) {
269     // APPLE_packed_pixels is only ever available on iOS, never Android.
270     d->pixel_format = GL_BGRA_EXT;
271     // Both Intel and PowerPC-era docs say to use GL_UNSIGNED_INT_8_8_8_8_REV.
272     d->pixel_type = GL_UNSIGNED_INT_8_8_8_8_REV;
273   } else {
274     d->pixel_format = GL_RGBA;
275     d->pixel_type = GL_UNSIGNED_BYTE;
276   }
277   // GL_ABGR_EXT/GL_UNSIGNED_BYTE is another possibilty that may have made more
278   // sense on PowerPC.
279 # endif // !HAVE_JWZGLES
280
281   // On really old systems, it would make sense to split textures
282   // into subsections, to work around the maximum texture size.
283 # ifndef HAVE_JWZGLES
284   d->gl_texture_npot_p = gluCheckExtension ((const GLubyte *)
285                                             "GL_ARB_texture_rectangle",
286                                             extensions);
287   d->gl_texture_target = d->gl_texture_npot_p ?
288                          GL_TEXTURE_RECTANGLE_EXT :
289                          GL_TEXTURE_2D;
290 # else
291   d->gl_texture_npot_p = jwzgles_gluCheckExtension
292       ((const GLubyte *) "GL_APPLE_texture_2D_limited_npot", extensions) ||
293     jwzgles_gluCheckExtension
294       ((const GLubyte *) "GL_OES_texture_npot", extensions) ||
295     jwzgles_gluCheckExtension // From PixelFlinger 1.4
296       ((const GLubyte *) "GL_ARB_texture_non_power_of_two", extensions);
297
298   d->gl_texture_target = GL_TEXTURE_2D;
299 # endif
300
301   Visual *v = &d->visual;
302   v->class      = TrueColor;
303   if (d->pixel_format == GL_BGRA_EXT) {
304     v->rgba_masks[0] = 0x00ff0000;
305     v->rgba_masks[1] = 0x0000ff00;
306     v->rgba_masks[2] = 0x000000ff;
307     v->rgba_masks[3] = 0xff000000;
308   } else {
309     Assert(d->pixel_format == GL_RGBA,
310            "jwxyz_gl_make_display: Unknown pixel_format");
311     for (unsigned i = 0; i != 4; ++i) {
312       union color_bytes color;
313       color.pixel = 0;
314       color.bytes[i] = 0xff;
315       v->rgba_masks[i] = color.pixel;
316     }
317   }
318
319   d->timers_data = jwxyz_sources_init (XtDisplayToApplicationContext (d));
320
321   d->window_background = BlackPixel(d,0);
322
323   d->main_window = w;
324   {
325     GLint max_texture_size;
326     glGetIntegerv (GL_MAX_TEXTURE_SIZE, &max_texture_size);
327     Log ("GL_MAX_TEXTURE_SIZE: %d\n", max_texture_size);
328   }
329  
330   glGenTextures (countof (d->textures), d->textures);
331
332   for (unsigned i = 0; i != countof (d->textures); i++) {
333     // TODO: Check for (ARB|EXT|NV)_texture_rectangle. (All three are alike.)
334     // Rectangle textures should be present on OS X with the following exceptions:
335     // - Generic renderer on PowerPC OS X 10.4 and earlier
336     // - ATI Rage 128
337     glBindTexture (d->gl_texture_target, d->textures[i]);
338     // TODO: This is all somewhere else. Refactor.
339     glTexParameteri (d->gl_texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
340     glTexParameteri (d->gl_texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
341
342     // This might be redundant for rectangular textures.
343 # ifndef HAVE_JWZGLES
344     const GLint wrap = GL_CLAMP;
345 # else  // HAVE_JWZGLES
346     const GLint wrap = GL_CLAMP_TO_EDGE;
347 # endif // HAVE_JWZGLES
348
349     // In OpenGL, CLAMP_TO_EDGE is OpenGL 1.2 or GL_SGIS_texture_edge_clamp.
350     // This is always present with OpenGL ES.
351     glTexParameteri (d->gl_texture_target, GL_TEXTURE_WRAP_S, wrap);
352     glTexParameteri (d->gl_texture_target, GL_TEXTURE_WRAP_T, wrap);
353   }
354
355   d->gc_function = GXcopy;
356   d->gc_alpha_allowed_p = False;
357
358   jwxyz_assert_display(d);
359   return d;
360 }
361
362 void
363 jwxyz_gl_free_display (Display *dpy)
364 {
365   Assert (dpy->vtbl == &gl_vtbl, "jwxyz-gl.c: bad vtable");
366
367   /* TODO: Go over everything. */
368
369   free (dpy->queue_vertex);
370   free (dpy->queue_color);
371
372   jwxyz_sources_free (dpy->timers_data);
373
374   free (dpy);
375 }
376
377
378 /* Call this when the View changes size or position.
379  */
380 void
381 jwxyz_window_resized (Display *dpy)
382 {
383   Assert (dpy->vtbl == &gl_vtbl, "jwxyz-gl.c: bad vtable");
384
385   const XRectangle *new_frame = jwxyz_frame (dpy->main_window);
386   unsigned new_width = new_frame->width;
387   unsigned new_height = new_frame->height;
388
389   Assert (new_width, "jwxyz_window_resized: No width.");
390   Assert (new_height, "jwxyz_window_resized: No height.");
391
392 /*if (cgc) w->cgc = cgc;
393   Assert (w->cgc, "no CGContext"); */
394
395   Log("resize: %d, %d\n", new_width, new_height);
396
397   jwxyz_gl_flush (dpy);
398   jwxyz_bind_drawable (dpy, dpy->main_window, dpy->main_window);
399
400   // TODO: What does the iPhone need?
401   
402   // iOS only: If the main_window is not the current_drawable, then set_matrices
403   // was already called in bind_drawable.
404   jwxyz_set_matrices (dpy, new_width, new_height, True);
405
406 /*
407   GLint draw_buffer;
408   glGetIntegerv (GL_DRAW_BUFFER, &draw_buffer);
409   
410   glDrawBuffer (GL_FRONT);
411   glClearColor (1, 0, 1, 0);
412   glClear (GL_COLOR_BUFFER_BIT);
413   glDrawBuffer (GL_BACK);
414   glClearColor (0, 1, 1, 0);
415   glClear (GL_COLOR_BUFFER_BIT);
416   
417   glDrawBuffer (draw_buffer); */
418   
419   // Stylish and attractive purple!
420   // glClearColor (1, 0, 1, 0.5);
421   // glClear (GL_COLOR_BUFFER_BIT);
422 }
423
424
425 static jwxyz_sources_data *
426 display_sources_data (Display *dpy)
427 {
428   return dpy->timers_data;
429 }
430
431
432 static Window
433 root (Display *dpy)
434 {
435   return dpy->main_window;
436 }
437
438 static Visual *
439 visual (Display *dpy)
440 {
441   return &dpy->visual;
442 }
443
444
445 /* GC attributes by usage and OpenGL implementation:
446
447    All drawing functions:
448    function                                | glLogicOp w/ GL_COLOR_LOGIC_OP
449    clip_x_origin, clip_y_origin, clip_mask | Stencil mask
450
451    Shape drawing functions:
452    foreground, background                  | glColor*
453
454    XDrawLines, XDrawRectangles, XDrawSegments:
455    line_width, cap_style, join_style       | Lotsa vertices
456
457    XFillPolygon:
458    fill_rule                               | Multiple GL_TRIANGLE_FANs
459
460    XDrawText:
461    font                                    | Cocoa, then OpenGL display lists.
462
463    alpha_allowed_p                         | GL_BLEND
464
465    antialias_p                             | Well, there's options:
466    * Multisampling would work, but that's something that would need to be set
467      per-Pixmap, not per-GC.
468    * GL_POINT, LINE, and POLYGON_SMOOTH are the old-school way of doing
469      this, but POINT_SMOOTH is unnecessary, and POLYGON_SMOOTH is missing from
470      GLES 1. All three are missing from GLES 2. Word on the street is that
471      these are deprecated anyway.
472    * Tiny textures with bilinear filtering to get the same effect as LINE_ and
473      POLYGON_SMOOTH. A bit tricky.
474    * Do nothing. Android hardware is very often high-DPI enough that
475      anti-aliasing doesn't matter all that much.
476
477    Nothing, really:
478    subwindow_mode
479  */
480
481 static void *
482 enqueue (Display *dpy, Drawable d, GC gc, int mode, size_t count,
483          unsigned long pixel)
484 {
485   if (dpy->queue_size &&
486       (dpy->gc_function != gc->gcv.function ||
487        dpy->gc_alpha_allowed_p != gc->gcv.alpha_allowed_p ||
488        dpy->queue_mode != mode ||
489        dpy->queue_drawable != d)) {
490     jwxyz_gl_flush (dpy);
491   }
492
493   jwxyz_bind_drawable (dpy, dpy->main_window, d);
494   jwxyz_gl_set_gc (dpy, gc);
495
496   if (mode == GL_TRIANGLE_STRIP)
497     Assert (count, "empty triangle strip");
498   // Use degenerate triangles to cut down on draw calls.
499   Bool prepend2 = mode == GL_TRIANGLE_STRIP && dpy->queue_size;
500
501   // ####: Primitive restarts should be used here when (if) they're available.
502   if (prepend2)
503     count += 2;
504
505   // TODO: Use glColor when we can get away with it.
506   size_t old_size = dpy->queue_size;
507   dpy->queue_size += count;
508   if (dpy->queue_size > dpy->queue_capacity) {
509     dpy->queue_capacity = dpy->queue_size * 2;
510
511     uint32_t *new_color = realloc (
512       dpy->queue_color, sizeof(*dpy->queue_color) * dpy->queue_capacity);
513     /* Allocate vertices as if they were always GLfloats. Otherwise, if
514        queue_vertex is allocated to hold GLshorts, then things get switched
515        to GLfloats, queue_vertex would be too small for the given capacity.
516      */
517     GLshort *new_vertex = realloc (
518       dpy->queue_vertex, sizeof(GLfloat) * 2 * dpy->queue_capacity);
519
520     if (!new_color || !new_vertex)
521       return NULL;
522
523     dpy->queue_color = new_color;
524     dpy->queue_vertex = new_vertex;
525   }
526
527   dpy->queue_mode = mode;
528   dpy->queue_drawable = d;
529
530   union color_bytes color;
531   // TODO: validate color
532   JWXYZ_QUERY_COLOR (dpy, pixel, 0xffull, color.bytes);
533   for (size_t i = 0; i != count; ++i) // TODO: wmemset when applicable.
534     dpy->queue_color[i + old_size] = color.pixel;
535
536   void *result = (char *)dpy->queue_vertex + old_size * 2 *
537     (mode == GL_TRIANGLE_STRIP ? sizeof(GLfloat) : sizeof(GLshort));
538   if (prepend2) {
539     dpy->queue_color[old_size] = dpy->queue_color[old_size - 1];
540     result = (GLfloat *)result + 4;
541   }
542   return result;
543 }
544
545
546 static void
547 finish_triangle_strip (Display *dpy, GLfloat *enqueue_result)
548 {
549   if (enqueue_result != dpy->queue_vertex) {
550     enqueue_result[-4] = enqueue_result[-6];
551     enqueue_result[-3] = enqueue_result[-5];
552     enqueue_result[-2] = enqueue_result[0];
553     enqueue_result[-1] = enqueue_result[1];
554   }
555 }
556
557
558 static void
559 set_clip_mask (GC gc)
560 {
561   Assert (!gc->gcv.clip_mask, "set_clip_mask: TODO");
562 }
563
564
565 static void
566 set_color (Display *dpy, unsigned long pixel, unsigned int depth,
567            Bool alpha_allowed_p)
568 {
569   jwxyz_validate_pixel (dpy, pixel, depth, alpha_allowed_p);
570
571   if (depth == 1) {
572     GLfloat f = pixel;
573     glColor4f (f, f, f, 1);
574   } else {
575     GLfloat rgba[4];
576     JWXYZ_QUERY_COLOR (dpy, pixel, 1.0f, rgba);
577     glColor4f (rgba[0], rgba[1], rgba[2], rgba[3]);
578   }
579 }
580
581 /* Pushes a GC context; sets Function and ClipMask. */
582 void
583 jwxyz_gl_set_gc (Display *dpy, GC gc)
584 {
585   int function;
586   Bool alpha_allowed_p;
587
588   // GC is NULL for XClearArea and XClearWindow.
589   if (gc) {
590     function = gc->gcv.function;
591     alpha_allowed_p = gc->gcv.alpha_allowed_p;
592     set_clip_mask (gc);
593   } else {
594     function = GXcopy;
595     alpha_allowed_p = False;
596     // TODO: Set null clip mask for NULL GC here.
597   }
598
599   /* GL_COLOR_LOGIC_OP: OpenGL 1.1. */
600   if (function != dpy->gc_function) {
601     dpy->gc_function = function;
602     if (function != GXcopy) {
603       /* Fun fact: The glLogicOp opcode constants are the same as the X11 GX*
604          function constants | GL_CLEAR.
605        */
606       glEnable (GL_COLOR_LOGIC_OP);
607       glLogicOp (gc->gcv.function | GL_CLEAR);
608     } else {
609       glDisable (GL_COLOR_LOGIC_OP);
610     }
611   }
612
613   /* Cocoa uses add/subtract/difference blending in place of logical ops.
614      It looks nice, but implementing difference blending in OpenGL appears to
615      require GL_KHR_blend_equation_advanced, and support for this is not
616      widespread.
617    */
618
619   if (alpha_allowed_p != dpy->gc_alpha_allowed_p) {
620     dpy->gc_alpha_allowed_p = alpha_allowed_p;
621     if (gc && gc->gcv.alpha_allowed_p) {
622       // TODO: Maybe move glBlendFunc to XCreatePixmap?
623       glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
624       glEnable (GL_BLEND);
625     } else {
626       glDisable (GL_BLEND);
627     }
628   }
629 }
630
631
632 static void
633 set_color_gc (Display *dpy, Drawable d, GC gc, unsigned long color)
634 {
635   jwxyz_gl_flush (dpy);
636   jwxyz_bind_drawable (dpy, dpy->main_window, d);
637   jwxyz_gl_set_gc (dpy, gc);
638
639   unsigned int depth;
640
641   if (gc) {
642     depth = gc->depth;
643
644     switch (gc->gcv.function) {
645       case GXset:   color = (depth == 1 ? 1 : WhitePixel(dpy,0)); break;
646       case GXclear: color = (depth == 1 ? 0 : BlackPixel(dpy,0)); break;
647     }
648   } else {
649     depth = visual_depth (NULL, NULL);
650   }
651
652   set_color (dpy, color, depth, gc ? gc->gcv.alpha_allowed_p : False);
653 }
654
655 /* Pushes a GC context; sets color to the foreground color.
656  */
657 static void
658 set_fg_gc (Display *dpy, Drawable d, GC gc)
659 {
660   set_color_gc (dpy, d, gc, gc->gcv.foreground);
661 }
662
663 static void
664 next_point(short *v, XPoint p, int mode)
665 {
666   switch (mode) {
667     case CoordModeOrigin:
668       v[0] = p.x;
669       v[1] = p.y;
670       break;
671     case CoordModePrevious:
672       v[0] += p.x;
673       v[1] += p.y;
674       break;
675     default:
676       Assert (False, "next_point: bad mode");
677       break;
678   }
679 }
680
681 static int
682 DrawPoints (Display *dpy, Drawable d, GC gc,
683             XPoint *points, int count, int mode)
684 {
685   short v[2] = {0, 0};
686
687   // TODO: XPoints can be fed directly to OpenGL.
688   GLshort *gl_points = enqueue (dpy, d, gc, GL_POINTS, count,
689                                 gc->gcv.foreground); // TODO: enqueue returns NULL.
690   for (unsigned i = 0; i < count; i++) {
691     next_point (v, points[i], mode);
692     gl_points[2 * i] = v[0];
693     gl_points[2 * i + 1] = v[1];
694   }
695
696   return 0;
697 }
698
699
700 static GLint
701 texture_internalformat (Display *dpy)
702 {
703 #ifdef HAVE_JWZGLES
704   return dpy->pixel_format;
705 #else
706   return GL_RGBA;
707 #endif
708 }
709
710 static GLenum
711 gl_pixel_type (const Display *dpy)
712 {
713   return dpy->pixel_type;
714 }
715
716 static void
717 clear_texture (Display *dpy)
718 {
719   glTexImage2D (dpy->gl_texture_target, 0, texture_internalformat(dpy), 0, 0,
720                 0, dpy->pixel_format, gl_pixel_type (dpy), NULL);
721 }
722
723 static void
724 set_white (void)
725 {
726 #ifdef HAVE_JWZGLES
727   glColor4f (1, 1, 1, 1);
728 #else
729   glColor3ub (0xff, 0xff, 0xff);
730 #endif
731 }
732
733
734 void
735 jwxyz_gl_flush (Display *dpy)
736 {
737   Assert (dpy->vtbl == &gl_vtbl, "jwxyz-gl.c: bad vtable");
738
739   if (!dpy->queue_size)
740     return;
741
742   // jwxyz_bind_drawable() and jwxyz_gl_set_gc() is called in enqueue().
743
744   glEnableClientState (GL_COLOR_ARRAY);
745   glEnableClientState (GL_VERTEX_ARRAY);
746   glDisableClientState (GL_TEXTURE_COORD_ARRAY);
747
748   // TODO: Use glColor instead of glColorPointer if there's just one color.
749   // TODO: Does OpenGL use both GL_COLOR_ARRAY and glColor at the same time?
750   set_white();
751
752   Bool shifted = dpy->queue_mode == GL_POINTS || dpy->queue_mode == GL_LINES;
753   if (shifted) {
754     glMatrixMode (GL_MODELVIEW);
755     glTranslatef (0.5, 0.5, 0);
756   }
757
758   glColorPointer (4, GL_UNSIGNED_BYTE, 0, dpy->queue_color);
759   glVertexPointer (2,
760                    dpy->queue_mode == GL_TRIANGLE_STRIP ? GL_FLOAT : GL_SHORT,
761                    0, dpy->queue_vertex);
762   glDrawArrays (dpy->queue_mode, 0, dpy->queue_size);
763
764   // TODO: This is right, right?
765   if (dpy->queue_mode == GL_LINES && dpy->queue_line_cap) {
766     Assert (!(dpy->queue_size % 2), "bad count for GL_LINES");
767     glColorPointer (4, GL_UNSIGNED_BYTE, sizeof(GLubyte) * 8,
768                     dpy->queue_color);
769     glVertexPointer (2, GL_SHORT, sizeof(GLshort) * 4,
770                      (GLshort *)dpy->queue_vertex + 2);
771     glDrawArrays (GL_POINTS, 0, dpy->queue_size / 2);
772   }
773
774   if (shifted)
775     glLoadIdentity ();
776
777   glDisableClientState (GL_COLOR_ARRAY);
778   glDisableClientState (GL_VERTEX_ARRAY);
779
780   dpy->queue_size = 0;
781 }
782
783
784 void
785 jwxyz_gl_copy_area_read_tex_image (Display *dpy, unsigned src_height,
786                                    int src_x, int src_y,
787                                    unsigned int width, unsigned int height,
788                                    int dst_x, int dst_y)
789 {
790 #  if defined HAVE_COCOA && !defined USE_IPHONE
791   /* TODO: Does this help? */
792   /* glFinish(); */
793 #  endif
794
795   /* TODO: Fix TestX11 + mode_preserve with this one. */
796
797   unsigned tex_w = width, tex_h = height;
798   if (!dpy->gl_texture_npot_p) {
799     tex_w = to_pow2(tex_w);
800     tex_h = to_pow2(tex_h);
801   }
802
803   GLint internalformat = texture_internalformat(dpy);
804
805   /* TODO: This probably shouldn't always be texture_rgba. */
806   glBindTexture (dpy->gl_texture_target, dpy->textures[texture_rgba]);
807
808   if (tex_w == width && tex_h == height) {
809     glCopyTexImage2D (dpy->gl_texture_target, 0, internalformat,
810                       src_x, src_height - src_y - height, width, height, 0);
811   } else {
812     glTexImage2D (dpy->gl_texture_target, 0, internalformat, tex_w, tex_h,
813                   0, dpy->pixel_format, gl_pixel_type(dpy), NULL);
814     glCopyTexSubImage2D (dpy->gl_texture_target, 0, 0, 0,
815                          src_x, src_height - src_y - height, width, height);
816   }
817 }
818
819 void
820 jwxyz_gl_copy_area_write_tex_image (Display *dpy, GC gc, int src_x, int src_y,
821                                     unsigned int width, unsigned int height,
822                                     int dst_x, int dst_y)
823 {
824   jwxyz_gl_set_gc (dpy, gc);
825
826   /* TODO: Copy-pasted from read_tex_image. */
827   unsigned tex_w = width, tex_h = height;
828   if (!dpy->gl_texture_npot_p) {
829     tex_w = to_pow2(tex_w);
830     tex_h = to_pow2(tex_h);
831   }
832
833   /* Must match what's in jwxyz_gl_copy_area_read_tex_image. */
834   glBindTexture (dpy->gl_texture_target, dpy->textures[texture_rgba]);
835
836   jwxyz_gl_draw_image (dpy->gl_texture_target, tex_w, tex_h, 0, 0,
837                        width, height, dst_x, dst_y);
838
839   clear_texture (dpy);
840 }
841
842
843 void
844 jwxyz_gl_draw_image (GLenum gl_texture_target,
845                      unsigned int tex_w, unsigned int tex_h,
846                      int src_x, int src_y,
847                      unsigned int width, unsigned int height,
848                      int dst_x, int dst_y)
849 {
850   set_white ();
851   glEnable (gl_texture_target);
852
853   glEnableClientState (GL_TEXTURE_COORD_ARRAY);
854   glEnableClientState (GL_VERTEX_ARRAY);
855     
856   /* TODO: Copied from XPutImage. Refactor. */
857   /* TODO: EXT_draw_texture or whatever it's called. */
858   GLfloat vertices[4][2] =
859   {
860     {dst_x, dst_y},
861     {dst_x, dst_y + height},
862     {dst_x + width, dst_y + height},
863     {dst_x + width, dst_y}
864   };
865
866   GLfloat
867     tex_x0 = src_x, tex_y0 = src_y + height,
868     tex_x1 = src_x + width, tex_y1 = src_y;
869
870 # ifndef HAVE_JWZGLES
871   if (gl_texture_target != GL_TEXTURE_RECTANGLE_EXT)
872 # endif
873   {
874     GLfloat mx = 1.0f / tex_w, my = 1.0f / tex_h;
875     tex_x0 *= mx;
876     tex_y0 *= my;
877     tex_x1 *= mx;
878     tex_y1 *= my;
879   }
880
881   GLfloat tex_coords[4][2] =
882   {
883     {tex_x0, tex_y0},
884     {tex_x0, tex_y1},
885     {tex_x1, tex_y1},
886     {tex_x1, tex_y0}
887   };
888
889   glVertexPointer (2, GL_FLOAT, 0, vertices);
890   glTexCoordPointer (2, GL_FLOAT, 0, tex_coords);
891   glDrawArrays (GL_TRIANGLE_FAN, 0, 4);
892
893   glDisable (gl_texture_target);
894 }
895
896 void
897 jwxyz_gl_copy_area_read_pixels (Display *dpy, Drawable src, Drawable dst,
898                                 GC gc, int src_x, int src_y,
899                                 unsigned int width, unsigned int height,
900                                 int dst_x, int dst_y)
901 {
902   XImage *img = XGetImage (dpy, src, src_x, src_y, width, height, ~0, ZPixmap);
903   XPutImage (dpy, dst, gc, img, 0, 0, dst_x, dst_y, width, height);
904   XDestroyImage (img);
905 }
906
907
908 static int
909 DrawLines (Display *dpy, Drawable d, GC gc, XPoint *points, int count,
910            int mode)
911 {
912   set_fg_gc (dpy, d, gc);
913
914   /* TODO: Thick lines
915    * Zero-length line segments
916    * Paths with zero length total (Remember line width, cap style.)
917    * Closed loops
918    */
919   
920   if (!count)
921     return 0;
922
923   GLshort *vertices = malloc(2 * sizeof(GLshort) * count); // TODO malloc NULL sigh
924   
925   glMatrixMode (GL_MODELVIEW);
926   glTranslatef (0.5f, 0.5f, 0);
927   
928   short p[2] = {0, 0};
929   for (unsigned i = 0; i < count; i++) {
930     next_point (p, points[i], mode);
931     vertices[2 * i] = p[0];
932     vertices[2 * i + 1] = p[1];
933   }
934   
935   glEnableClientState (GL_VERTEX_ARRAY);
936   glDisableClientState (GL_TEXTURE_COORD_ARRAY);
937   glVertexPointer (2, GL_SHORT, 0, vertices);
938   glDrawArrays (GL_LINE_STRIP, 0, count);
939   
940   free (vertices);
941
942   if (gc->gcv.cap_style != CapNotLast) {
943     // TODO: How does this look with multisampling?
944     // TODO: Disable me for closed loops.
945     glVertexPointer (2, GL_SHORT, 0, p);
946     glDrawArrays (GL_POINTS, 0, 1);
947   }
948
949   glLoadIdentity ();
950   
951   return 0;
952 }
953
954
955 // Turn line segment into parallelogram based on line_width
956 //
957 // TODO: Fix epicycle hack with large thickness, and truchet line segment ends
958 //
959 static void
960 drawThickLine (Display *dpy, Drawable d, GC gc, int line_width,
961                XSegment *segments)
962 {
963     double dx, dy, di, m, angle;
964     int sx1, sx2, sy1, sy2;
965
966     sx1 = segments->x1;
967     sy1 = segments->y1;
968     sx2 = segments->x2;
969     sy2 = segments->y2;
970
971     dx = sx1 - sx2;
972     dy = sy1 - sy2;
973     di = sqrt(dx * dx + dy * dy);
974     dx = dx / di;
975     dy = dy / di;
976     m = dy / dx;
977
978     angle = atan(m); 
979
980     float sn = sin(angle);
981     float cs = cos(angle);
982     float line_width_f = (float) line_width;
983
984     float wsn = line_width_f * (sn/2);
985     float csn = line_width_f * (cs/2);
986
987     float x3 = sx1 - wsn;
988     float y3 = sy1 + csn;
989     float x4 = sx1 + wsn;
990     float y4 = sy1 - csn;
991
992     float x5 = sx2 - wsn;
993     float y5 = sy2 + csn;
994     float x6 = sx2 + wsn;
995     float y6 = sy2 - csn;
996
997     GLfloat *coords = enqueue (dpy, d, gc, GL_TRIANGLE_STRIP, 4,
998                                gc->gcv.foreground);
999     coords[0] = x3;
1000     coords[1] = y3;
1001     coords[2] = x4;
1002     coords[3] = y4;
1003     coords[4] = x5;
1004     coords[5] = y5;
1005     coords[6] = x6;
1006     coords[7] = y6;
1007     finish_triangle_strip (dpy, coords);
1008 }
1009
1010
1011 static int
1012 DrawSegments (Display *dpy, Drawable d, GC gc, XSegment *segments, int count)
1013 {
1014   /* TODO: Caps on thick lines. */
1015   /* Thin lines <= 1px are offset by +0.5; thick lines are not. */
1016
1017   if (count == 1 && gc->gcv.line_width > 1) {
1018     drawThickLine (dpy, d, gc, gc->gcv.line_width, segments);
1019   }
1020   else {
1021     if (dpy->queue_line_cap != (gc->gcv.cap_style != CapNotLast))
1022       jwxyz_gl_flush (dpy);
1023     dpy->queue_line_cap = gc->gcv.cap_style != CapNotLast;
1024
1025     // TODO: Static assert here.
1026     Assert (sizeof(XSegment) == sizeof(short) * 4 &&
1027             sizeof(GLshort) == sizeof(short) &&
1028             offsetof(XSegment, x1) == 0 &&
1029             offsetof(XSegment, x2) == 4,
1030             "XDrawSegments: Data alignment mix-up.");
1031
1032     memcpy (enqueue(dpy, d, gc, GL_LINES, count * 2, gc->gcv.foreground),
1033             segments, count * sizeof(XSegment));
1034   }
1035
1036   return 0;
1037 }
1038
1039
1040 static int
1041 ClearWindow (Display *dpy, Window win)
1042 {
1043   Assert (win == dpy->main_window, "not a window");
1044
1045   jwxyz_gl_flush (dpy);
1046   jwxyz_bind_drawable (dpy, win, win);
1047
1048   GLfloat color[4];
1049   JWXYZ_QUERY_COLOR (dpy, dpy->window_background, 1.0f, color);
1050
1051   glClearColor (color[0], color[1], color[2], 1);
1052   glClear (GL_COLOR_BUFFER_BIT);
1053   return True;
1054 }
1055
1056 static unsigned long *
1057 window_background (Display *dpy)
1058 {
1059   return &dpy->window_background;
1060 }
1061
1062 static void
1063 fill_rects (Display *dpy, Drawable d, GC gc,
1064             const XRectangle *rectangles, unsigned long nrectangles,
1065             unsigned long pixel)
1066 {
1067   for (unsigned long i = 0; i != nrectangles; ++i) {
1068     const XRectangle *r = &rectangles[i];
1069     GLfloat *coords = enqueue (dpy, d, gc, GL_TRIANGLE_STRIP, 4, pixel);
1070     coords[0] = r->x;
1071     coords[1] = r->y;
1072     coords[2] = r->x;
1073     coords[3] = r->y + r->height;
1074     coords[4] = r->x + r->width;
1075     coords[5] = r->y;
1076     coords[6] = r->x + r->width;
1077     coords[7] = r->y + r->height;
1078     finish_triangle_strip (dpy, coords);
1079   }
1080 }
1081
1082
1083 static int
1084 FillPolygon (Display *dpy, Drawable d, GC gc,
1085              XPoint *points, int npoints, int shape, int mode)
1086 {
1087   set_fg_gc(dpy, d, gc);
1088   
1089   // TODO: Re-implement the GLU tesselation functions.
1090
1091   /* Complex: Pedal, and for some reason Attraction, Mountain, Qix, SpeedMine, Starfish
1092    * Nonconvex: Goop, Pacman, Rocks, Speedmine
1093    *
1094    * We currently do Nonconvex with the simple-to-implement ear clipping
1095    * algorithm, but in the future we can replace that with an algorithm
1096    * with slower big-O growth
1097    *
1098    */
1099   
1100   
1101   // TODO: Feed vertices straight to OpenGL for CoordModeOrigin.
1102
1103   if (shape == Convex) {
1104
1105     GLshort *vertices = malloc(npoints * sizeof(GLshort) * 2); // TODO: Oh look, another unchecked malloc.
1106     short v[2] = {0, 0};
1107   
1108     for (unsigned i = 0; i < npoints; i++) {
1109       next_point(v, points[i], mode);
1110       vertices[2 * i] = v[0];
1111       vertices[2 * i + 1] = v[1];
1112     }
1113
1114     glEnableClientState (GL_VERTEX_ARRAY);
1115     glDisableClientState (GL_TEXTURE_COORD_ARRAY);
1116
1117     glVertexPointer (2, GL_SHORT, 0, vertices);
1118     glDrawArrays (GL_TRIANGLE_FAN, 0, npoints);
1119
1120     free(vertices);
1121
1122   } else if (shape == Nonconvex) {
1123
1124     // TODO: assert that x,y of first and last point match, as that is assumed
1125
1126     linked_point *root;
1127     root = (linked_point *) malloc( sizeof(linked_point) );
1128     set_points_list(points,npoints,root);
1129     traverse_points_list(root);
1130
1131   } else {
1132     Assert((shape == Convex || shape == Nonconvex),
1133            "XFillPolygon: (TODO) Unimplemented shape");
1134   }
1135
1136   return 0;
1137 }
1138
1139 #define radians(DEG) ((DEG) * M_PI / 180.0)
1140 #define degrees(RAD) ((RAD) * 180.0 / M_PI)
1141
1142 static void
1143 arc_xy(GLfloat *p, double cx, double cy, double w2, double h2, double theta)
1144 {
1145   p[0] = cos(theta) * w2 + cx;
1146   p[1] = -sin(theta) * h2 + cy;
1147 }
1148
1149 static unsigned
1150 mod_neg(int a, unsigned b)
1151 {
1152   /* Normal modulus is implementation defined for negative numbers. This is 
1153    * well-defined such that the repeating pattern for a >= 0 is maintained for 
1154    * a < 0. */
1155   return a < 0 ? (b - 1) - (-(a + 1) % b) : a % b;
1156 }
1157
1158 /* TODO: Fill in arcs with line width > 1 */
1159 static int
1160 draw_arc (Display *dpy, Drawable d, GC gc, int x, int y,
1161           unsigned int width, unsigned int height,
1162           int angle1, int angle2, Bool fill_p)
1163 {
1164     int gglw = gc->gcv.line_width;
1165
1166     if (fill_p || gglw <= 1) {
1167         draw_arc_gl (dpy, d, gc, x, y, width, height, angle1, angle2, fill_p);
1168     }
1169     else {
1170         int w1, w2, h1, h2, gglwh;
1171         w1 = width + gglw;
1172         h1 = height + gglw;
1173         h2 = height - gglw;
1174         w2 = width - gglw;
1175         gglwh = gglw / 2;
1176         int x1 = x - gglwh;
1177         int x2 = x + gglwh;
1178         int y1 = y - gglwh;
1179         int y2 = y + gglwh;
1180         //draw_arc_gl (dpy, d, gc, x, y, width, height, angle1, angle2, fill_p);
1181         draw_arc_gl (dpy, d, gc, x1, y1, w1, h1, angle1, angle2, fill_p);
1182         draw_arc_gl (dpy, d, gc, x2, y2, w2, h2, angle1, angle2, fill_p);
1183     }
1184     return 0;
1185 }
1186
1187
1188 int
1189 draw_arc_gl (Display *dpy, Drawable d, GC gc, int x, int y,
1190           unsigned int width, unsigned int height,
1191           int angle1, int angle2, Bool fill_p)
1192 {
1193   set_fg_gc(dpy, d, gc);
1194
1195   /* Let's say the number of line segments needed to make a convincing circle is
1196      4*sqrt(radius). (But these arcs aren't necessarily circular arcs...) */
1197
1198   double w2 = width * 0.5f, h2 = height * 0.5f;
1199   double a, b; /* Semi-major/minor axes. */
1200   if(w2 > h2) {
1201     a = w2;
1202     b = h2;
1203   } else {
1204     a = h2;
1205     b = w2;
1206   }
1207   
1208   const double two_pi = 2 * M_PI;
1209
1210   double amb = a - b, apb = a + b;
1211   double h = (amb * amb) / (apb * apb);
1212   // TODO: Math cleanup.
1213   double C_approx = M_PI * apb * (1 + 3 * h / (10 + sqrtf(4 - 3 * h)));
1214   double segments_f = 4 * sqrtf(C_approx / (2 * M_PI));
1215
1216   // TODO: Explain how drawing works what with the points of overlapping arcs
1217   // matching up.
1218  
1219 #if 1
1220   unsigned segments_360 = segments_f;
1221   
1222   /* TODO: angle2 == 0. This is a tilted square with CapSquare. */
1223   /* TODO: color, thick lines, CapNotLast for thin lines */
1224   /* TODO: Transformations. */
1225
1226   double segment_angle = two_pi / segments_360;
1227
1228   const unsigned deg64 = 360 * 64;
1229   const double rad_from_deg64 = two_pi / deg64;
1230   
1231   if (angle2 < 0) {
1232     angle1 += angle2;
1233     angle2 = -angle2;
1234   }
1235
1236   angle1 = mod_neg(angle1, deg64); // TODO: Is this OK? Consider negative numbers.
1237
1238   if (angle2 > deg64)
1239     angle2 = deg64; // TODO: Handle circles special.
1240   
1241   double
1242     angle1_f = angle1 * rad_from_deg64,
1243     angle2_f = angle2 * rad_from_deg64;
1244   
1245   if (angle2_f > two_pi) // TODO: Move this up.
1246     angle2_f = two_pi;
1247   
1248   double segment1_angle_part = fmodf(angle1_f, segment_angle);
1249   
1250   unsigned segment1 = ((angle1_f - segment1_angle_part) / segment_angle) + 1.5;
1251
1252   double angle_2r = angle2_f - segment1_angle_part;
1253   unsigned segments = angle_2r / segment_angle;
1254   
1255   GLfloat cx = x + w2, cy = y + h2;
1256
1257   GLfloat *data = malloc((segments + 3) * sizeof(GLfloat) * 2); // TODO: Check result.
1258   
1259   GLfloat *data_ptr = data;
1260   if (fill_p) {
1261     data_ptr[0] = cx;
1262     data_ptr[1] = cy;
1263     data_ptr += 2;
1264   }
1265   
1266   arc_xy (data_ptr, cx, cy, w2, h2, angle1_f);
1267   data_ptr += 2;
1268   
1269   for (unsigned s = 0; s != segments; ++s) {
1270     // TODO: Make sure values of theta for the following arc_xy call are between
1271     // angle1_f and angle1_f + angle2_f.
1272     arc_xy (data_ptr, cx, cy, w2, h2, (segment1 + s) * segment_angle);
1273     data_ptr += 2;
1274   }
1275   
1276   arc_xy (data_ptr, cx, cy, w2, h2, angle1_f + angle2_f);
1277   data_ptr += 2;
1278
1279   glDisableClientState (GL_TEXTURE_COORD_ARRAY);
1280   glEnableClientState (GL_VERTEX_ARRAY);
1281   
1282   glVertexPointer (2, GL_FLOAT, 0, data);
1283   glDrawArrays (fill_p ? GL_TRIANGLE_FAN : GL_LINE_STRIP,
1284                 0,
1285                 (GLsizei)((data_ptr - data) / 2));
1286
1287   free(data);
1288   
1289 #endif
1290   
1291 #if 0
1292   unsigned segments = segments_f * (fabs(angle2) / (360 * 64));
1293  
1294   glBegin (fill_p ? GL_TRIANGLE_FAN : GL_LINE_STRIP);
1295   
1296   if (fill_p /* && gc->gcv.arc_mode == ArcPieSlice */)
1297     glVertex2f (cx, cy);
1298   
1299   /* TODO: This should fix the middle points of the arc so that the starting and ending points are OK. */
1300   
1301   float to_radians = 2 * M_PI / (360 * 64);
1302   float theta = angle1 * to_radians, d_theta = angle2 * to_radians / segments;
1303   
1304   for (unsigned s = 0; s != segments + 1; ++s) /* TODO: This is the right number of segments, yes? */
1305   {
1306     glVertex2f(cos(theta) * w2 + cx, -sin(theta) * h2 + cy);
1307     theta += d_theta;
1308   }
1309   
1310   glEnd ();
1311 #endif
1312   
1313   return 0;
1314 }
1315
1316
1317 static XGCValues *
1318 gc_gcv (GC gc)
1319 {
1320   return &gc->gcv;
1321 }
1322
1323
1324 static unsigned int
1325 gc_depth (GC gc)
1326 {
1327   return gc->depth;
1328 }
1329
1330
1331 static GC
1332 CreateGC (Display *dpy, Drawable d, unsigned long mask, XGCValues *xgcv)
1333 {
1334   struct jwxyz_GC *gc = (struct jwxyz_GC *) calloc (1, sizeof(*gc));
1335   gc->depth = jwxyz_drawable_depth (d);
1336
1337   jwxyz_gcv_defaults (dpy, &gc->gcv, gc->depth);
1338   XChangeGC (dpy, gc, mask, xgcv);
1339   return gc;
1340 }
1341
1342
1343 static int
1344 FreeGC (Display *dpy, GC gc)
1345 {
1346   if (gc->gcv.font)
1347     XUnloadFont (dpy, gc->gcv.font);
1348
1349   // TODO
1350 /*
1351   Assert (!!gc->gcv.clip_mask == !!gc->clip_mask, "GC clip mask mixup");
1352
1353   if (gc->gcv.clip_mask) {
1354     XFreePixmap (dpy, gc->gcv.clip_mask);
1355     CGImageRelease (gc->clip_mask);
1356   }
1357 */
1358   free (gc);
1359   return 0;
1360 }
1361
1362
1363 static int
1364 PutImage (Display *dpy, Drawable d, GC gc, XImage *ximage,
1365           int src_x, int src_y, int dest_x, int dest_y,
1366           unsigned int w, unsigned int h)
1367 {
1368   jwxyz_assert_display (dpy);
1369  
1370   const XRectangle *wr = jwxyz_frame (d);
1371
1372   Assert (gc, "no GC");
1373   Assert ((w < 65535), "improbably large width");
1374   Assert ((h < 65535), "improbably large height");
1375   Assert ((src_x  < 65535 && src_x  > -65535), "improbably large src_x");
1376   Assert ((src_y  < 65535 && src_y  > -65535), "improbably large src_y");
1377   Assert ((dest_x < 65535 && dest_x > -65535), "improbably large dest_x");
1378   Assert ((dest_y < 65535 && dest_y > -65535), "improbably large dest_y");
1379
1380   // Clip width and height to the bounds of the Drawable
1381   //
1382   if (dest_x + w > wr->width) {
1383     if (dest_x > wr->width)
1384       return 0;
1385     w = wr->width - dest_x;
1386   }
1387   if (dest_y + h > wr->height) {
1388     if (dest_y > wr->height)
1389       return 0;
1390     h = wr->height - dest_y;
1391   }
1392   if (w <= 0 || h <= 0)
1393     return 0;
1394
1395   // Clip width and height to the bounds of the XImage
1396   //
1397   if (src_x + w > ximage->width) {
1398     if (src_x > ximage->width)
1399       return 0;
1400     w = ximage->width - src_x;
1401   }
1402   if (src_y + h > ximage->height) {
1403     if (src_y > ximage->height)
1404       return 0;
1405     h = ximage->height - src_y;
1406   }
1407   if (w <= 0 || h <= 0)
1408     return 0;
1409
1410   /* Assert (d->win */
1411
1412   if (jwxyz_dumb_drawing_mode(dpy, d, gc, dest_x, dest_y, w, h))
1413     return 0;
1414
1415   jwxyz_gl_flush (dpy);
1416   jwxyz_bind_drawable (dpy, dpy->main_window, d);
1417   jwxyz_gl_set_gc (dpy, gc);
1418
1419   int bpl = ximage->bytes_per_line;
1420   int bpp = ximage->bits_per_pixel;
1421
1422   char *tex_data;
1423   unsigned src_w;
1424   GLint tex_internalformat;
1425   GLenum tex_format, tex_type;
1426   unsigned tex_index;
1427
1428   if (bpp == 32) {
1429     tex_data = ximage->data + src_y * bpl + (src_x * 4);
1430
1431     jwxyz_assert_display(dpy);
1432     
1433     /* There probably won't be any hacks that do this, but... */
1434     Assert (!(bpl % 4), "XPutImage: bytes_per_line not divisible by four.");
1435     
1436     tex_internalformat = texture_internalformat(dpy);
1437     tex_format = dpy->pixel_format;
1438     tex_type = gl_pixel_type(dpy);
1439     tex_index = texture_rgba;
1440
1441     /* GL_UNPACK_ROW_LENGTH is not allowed to be negative. (sigh) */
1442 # ifndef HAVE_JWZGLES
1443     src_w = w;
1444     glPixelStorei (GL_UNPACK_ROW_LENGTH, src_w);
1445 # else
1446     src_w = bpl / 4;
1447 # endif
1448
1449     // glPixelStorei (GL_UNPACK_ALIGNMENT, 4); // Probably unnecessary.
1450
1451     set_white ();
1452   } else {
1453     Assert (bpp == 1, "expected 1 or 32 bpp");
1454     Assert ((src_x % 8) == 0,
1455             "XPutImage with non-byte-aligned 1bpp X offset not implemented");
1456
1457     const char *src_data = ximage->data + src_y * bpl + (src_x / 8);
1458     unsigned w8 = (w + 7) / 8;
1459
1460     src_w = w8 * 8;
1461
1462     tex_data = malloc(src_w * h);
1463
1464 #if 0
1465     {
1466       char s[10240];
1467       int x, y, o;
1468       Log("#PI ---------- %d %d %08lx %08lx",
1469           jwxyz_drawable_depth(d), ximage->depth,
1470           (unsigned long)d, (unsigned long)ximage);
1471       for (y = 0; y < ximage->height; y++) {
1472         o = 0;
1473         for (x = 0; x < ximage->width; x++) {
1474           unsigned long b = XGetPixel(ximage, x, y);
1475           s[o++] = (   (b & 0xFF000000)
1476                     ? ((b & 0x00FFFFFF) ? '#' : '-')
1477                     : ((b & 0x00FFFFFF) ? '+' : ' '));
1478         }
1479         s[o] = 0;
1480         Log("#PI [%s]",s);
1481       }
1482       Log("# PI ----------");
1483     }
1484 #endif
1485     uint32_t *data_out = (uint32_t *)tex_data;
1486     for(unsigned y = h; y; --y) {
1487       for(unsigned x = 0; x != w8; ++x) {
1488         // TODO: Does big endian work here?
1489         uint8_t byte = src_data[x];
1490         uint32_t word = byte;
1491         word = (word & 0x3) | ((word & 0xc) << 14);
1492         word = (word & 0x00010001) | ((word & 0x00020002) << 7);
1493         data_out[x << 1] = (word << 8) - word;
1494
1495         word = byte >> 4;
1496         word = (word & 0x3) | ((word & 0xc) << 14);
1497         word = (word & 0x00010001) | ((word & 0x00020002) << 7);
1498         data_out[(x << 1) | 1] = (word << 8) - word;
1499       }
1500       src_data += bpl;
1501       data_out += src_w / 4;
1502     }
1503 #if 0
1504     {
1505       char s[10240];
1506       int x, y, o;
1507       Log("#P2 ----------");
1508       for (y = 0; y < ximage->height; y++) {
1509         o = 0;
1510         for (x = 0; x < ximage->width; x++) {
1511           unsigned long b = ((uint8_t *)tex_data)[y * w + x];
1512           s[o++] = (   (b & 0xFF000000)
1513                     ? ((b & 0x00FFFFFF) ? '#' : '-')
1514                     : ((b & 0x00FFFFFF) ? '+' : ' '));
1515         }
1516         s[o] = 0;
1517         Log("#P2 [%s]",s);
1518       }
1519       Log("# P2 ----------");
1520     }
1521 #endif
1522
1523     tex_internalformat = GL_LUMINANCE;
1524     tex_format = GL_LUMINANCE;
1525     tex_type = GL_UNSIGNED_BYTE;
1526     tex_index = texture_mono;
1527
1528     // glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
1529
1530     set_color (dpy, gc->gcv.foreground, gc->depth, gc->gcv.alpha_allowed_p);
1531     // TODO: Deal with the background color.
1532   }
1533
1534 # if 1 // defined HAVE_JWZGLES
1535   // Regular OpenGL uses GL_TEXTURE_RECTANGLE_EXT in place of GL_TEXTURE_2D.
1536   // TODO: Make use of OES_draw_texture.
1537
1538   unsigned tex_w = src_w, tex_h = h;
1539   if (!dpy->gl_texture_npot_p) {
1540     tex_w = to_pow2(tex_w);
1541     tex_h = to_pow2(tex_h);
1542   }
1543
1544   glBindTexture (dpy->gl_texture_target, dpy->textures[tex_index]);
1545
1546   // A fun project: reimplement xshm.c by means of a PBO using
1547   // GL_MAP_UNSYNCHRONIZED_BIT.
1548
1549   // TODO: Would using glTexSubImage2D exclusively be faster?
1550   if (tex_w == src_w && tex_h == h) {
1551     glTexImage2D (dpy->gl_texture_target, 0, tex_internalformat, tex_w, tex_h,
1552                   0, tex_format, tex_type, tex_data);
1553   } else {
1554     // TODO: Sampling the last row might be a problem if src_x != 0.
1555     glTexImage2D (dpy->gl_texture_target, 0, tex_internalformat, tex_w, tex_h,
1556                   0, tex_format, tex_type, NULL);
1557     glTexSubImage2D (dpy->gl_texture_target, 0, 0, 0, src_w, h,
1558                      tex_format, tex_type, tex_data);
1559   }
1560
1561   if (bpp == 1)
1562     free(tex_data);
1563
1564   // TODO: This looks a lot like jwxyz_gl_draw_image. Refactor.
1565
1566   // glEnable (dpy->gl_texture_target);
1567   // glColor4f (0.5, 0, 1, 1);
1568   glEnable (dpy->gl_texture_target);
1569   glEnableClientState (GL_VERTEX_ARRAY);
1570   glEnableClientState (GL_TEXTURE_COORD_ARRAY);
1571
1572   // TODO: Why are these ever turned on in the first place?
1573   glDisableClientState (GL_COLOR_ARRAY);
1574   glDisableClientState (GL_NORMAL_ARRAY);
1575   // glDisableClientState (GL_TEXTURE_COORD_ARRAY);
1576
1577   GLfloat vertices[4][2] =
1578   {
1579     {dest_x, dest_y},
1580     {dest_x, dest_y + h},
1581     {dest_x + w, dest_y + h},
1582     {dest_x + w, dest_y}
1583   };
1584
1585   GLfloat texcoord_w, texcoord_h;
1586 #  ifndef HAVE_JWZGLES
1587   if (dpy->gl_texture_target == GL_TEXTURE_RECTANGLE_EXT) {
1588     texcoord_w = w;
1589     texcoord_h = h;
1590   } else
1591 #  endif /* HAVE_JWZGLES */
1592   {
1593     texcoord_w = (double)w / tex_w;
1594     texcoord_h = (double)h / tex_h;
1595   }
1596
1597   GLfloat tex_coords[4][2];
1598   tex_coords[0][0] = 0;
1599   tex_coords[0][1] = 0;
1600   tex_coords[1][0] = 0;
1601   tex_coords[1][1] = texcoord_h;
1602   tex_coords[2][0] = texcoord_w;
1603   tex_coords[2][1] = texcoord_h;
1604   tex_coords[3][0] = texcoord_w;
1605   tex_coords[3][1] = 0;
1606
1607   glVertexPointer (2, GL_FLOAT, 0, vertices);
1608   glTexCoordPointer (2, GL_FLOAT, 0, tex_coords);
1609   glDrawArrays (GL_TRIANGLE_FAN, 0, 4);
1610
1611 //clear_texture();
1612   glDisable (dpy->gl_texture_target);
1613 # else
1614   glRasterPos2i (dest_x, dest_y);
1615   glPixelZoom (1, -1);
1616   jwxyz_assert_display (dpy);
1617   glDrawPixels (w, h, dpy->pixel_format, gl_pixel_type(dpy), data);
1618 # endif
1619
1620   jwxyz_assert_gl ();
1621
1622   return 0;
1623 }
1624
1625 /* At the moment only XGetImage and get_xshm_image use XGetSubImage. */
1626 /* #### Twang calls XGetImage on the window intending to get a
1627    buffer full of black.  This is returning a buffer full of white
1628    instead of black for some reason. */
1629 static XImage *
1630 GetSubImage (Display *dpy, Drawable d, int x, int y,
1631              unsigned int width, unsigned int height,
1632              unsigned long plane_mask, int format,
1633              XImage *dest_image, int dest_x, int dest_y)
1634 {
1635   Assert ((width  < 65535), "improbably large width");
1636   Assert ((height < 65535), "improbably large height");
1637   Assert ((x < 65535 && x > -65535), "improbably large x");
1638   Assert ((y < 65535 && y > -65535), "improbably large y");
1639
1640   jwxyz_gl_flush (dpy);
1641   jwxyz_bind_drawable (dpy, dpy->main_window, d);
1642   
1643   // TODO: What if this reads off the edge? What is supposed to happen?
1644
1645   {
1646     // In case the caller tries to write off the edge.
1647     int
1648       max_width = dest_image->width - dest_x,
1649       max_height = dest_image->height - dest_y;
1650
1651     if (width > max_width) {
1652       width = max_width;
1653     }
1654     
1655     if (height > max_height) {
1656       height = max_height;
1657     }
1658   }
1659   
1660   Assert (jwxyz_drawable_depth (d) == dest_image->depth, "XGetSubImage: depth mismatch");
1661   
1662   if (dest_image->depth == visual_depth (NULL, NULL)) {
1663     Assert (!(dest_image->bytes_per_line % 4), "XGetSubImage: bytes_per_line not divisible by 4");
1664     unsigned pixels_per_line = dest_image->bytes_per_line / 4;
1665 #ifdef HAVE_JWZGLES
1666     Assert (pixels_per_line == width, "XGetSubImage: (TODO) pixels_per_line != width");
1667 #else
1668     glPixelStorei (GL_PACK_ROW_LENGTH, pixels_per_line);
1669 #endif
1670     glPixelStorei (GL_PACK_ALIGNMENT, 4);
1671     
1672     uint32_t *dest_data = (uint32_t *)dest_image->data + pixels_per_line * dest_y + dest_x;
1673     
1674     glReadPixels (x, jwxyz_frame (d)->height - (y + height), width, height,
1675                   dpy->pixel_format, gl_pixel_type(dpy), dest_data);
1676
1677     /* Flip this upside down. :( */
1678     uint32_t *top = dest_data;
1679     uint32_t *bottom = dest_data + pixels_per_line * (height - 1);
1680     for (unsigned y = height / 2; y; --y) {
1681       for (unsigned x = 0; x != width; ++x) {
1682         uint32_t px = top[x];
1683         top[x] = bottom[x];
1684         bottom[x] = px;
1685       }
1686       top += pixels_per_line;
1687       bottom -= pixels_per_line;
1688     }
1689   } else {
1690
1691     uint32_t *rgba_image = malloc(width * height * 4);
1692     Assert (rgba_image, "not enough memory");
1693
1694     // Must be GL_RGBA; GL_RED isn't available.
1695     glReadPixels (x, jwxyz_frame (d)->height - (y + height), width, height,
1696                   GL_RGBA, GL_UNSIGNED_BYTE, rgba_image);
1697
1698     Assert (!(dest_x % 8), "XGetSubImage: dest_x not byte-aligned");
1699     uint8_t *top =
1700       (uint8_t *)dest_image->data + dest_image->bytes_per_line * dest_y
1701       + dest_x / 8;
1702 #if 0
1703     {
1704       char s[10240];
1705       Log("#GI ---------- %d %d  %d x %d %08lx", 
1706           jwxyz_drawable_depth(d), dest_image->depth,
1707           width, height,
1708           (unsigned long) d);
1709       for (int y = 0; y < height; y++) {
1710         int x;
1711         for (x = 0; x < width; x++) {
1712           unsigned long b = rgba_image[(height-y-1) * width + x];
1713           s[x] = (   (b & 0xFF000000)
1714                   ? ((b & 0x00FFFFFF) ? '#' : '-')
1715                   : ((b & 0x00FFFFFF) ? '+' : ' '));
1716         }
1717         s[x] = 0;
1718         Log("#GI [%s]",s);
1719       }
1720       Log("#GI ----------");
1721     }
1722 #endif
1723     const uint32_t *bottom = rgba_image + width * (height - 1);
1724     for (unsigned y = height; y; --y) {
1725       memset (top, 0, width / 8);
1726       for (unsigned x = 0; x != width; ++x) {
1727         if (bottom[x] & 0x80)
1728           top[x >> 3] |= (1 << (x & 7));
1729       }
1730       top += dest_image->bytes_per_line;
1731       bottom -= width;
1732     }
1733
1734     free (rgba_image);
1735   }
1736
1737   return dest_image;
1738 }
1739
1740
1741 #if 0
1742 static Pixmap
1743 copy_pixmap (Display *dpy, Pixmap p)
1744 {
1745   if (!p) return 0;
1746   Assert (p->type == PIXMAP, "not a pixmap");
1747
1748   Pixmap p2 = 0;
1749
1750   Window root;
1751   int x, y;
1752   unsigned int width, height, border_width, depth;
1753   if (XGetGeometry (dpy, p, &root,
1754                     &x, &y, &width, &height, &border_width, &depth)) {
1755     XGCValues gcv;
1756     gcv.function = GXcopy;
1757     GC gc = XCreateGC (dpy, p, GCFunction, &gcv);
1758     if (gc) {
1759       p2 = XCreatePixmap (dpy, p, width, height, depth);
1760       if (p2)
1761         XCopyArea (dpy, p, p2, gc, 0, 0, width, height, 0, 0);
1762       XFreeGC (dpy, gc);
1763     }
1764   }
1765
1766   Assert (p2, "could not copy pixmap");
1767
1768   return p2;
1769 }
1770 #endif
1771
1772
1773 static int
1774 SetClipMask (Display *dpy, GC gc, Pixmap m)
1775 {
1776   Log ("TODO: No clip masks yet");
1777   /* Protip: Do glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1778      clearing just the stencil buffer in a packed depth/stencil arrangement is
1779      slower than the above. Adreno recommends this, but other GPUs probably
1780      benefit as well.
1781    */
1782   return 0;
1783 }
1784
1785 static int
1786 SetClipOrigin (Display *dpy, GC gc, int x, int y)
1787 {
1788   gc->gcv.clip_x_origin = x;
1789   gc->gcv.clip_y_origin = y;
1790   return 0;
1791 }
1792
1793 void set_points_list(XPoint *points, int npoints, linked_point *root)
1794 {
1795     linked_point *current;  
1796
1797     current = root;
1798     for (int i = 0; i < npoints - 2 ; i++) {
1799         current->x = points[i].x;
1800         current->y = points[i].y;
1801         current->next = (linked_point *) malloc(sizeof(linked_point)); 
1802         current = current->next;
1803     }
1804     current->x = points[npoints-2].x;
1805     current->y = points[npoints-2].y;
1806     current->next = root;
1807 }
1808
1809
1810 double compute_edge_length(linked_point * a, linked_point * b)
1811 {
1812
1813     int xdiff, ydiff, xsq, ysq, added;
1814     double xy_add, edge_length;
1815
1816     xdiff = a->x - b->x;
1817     ydiff = a->y - b->y;
1818     xsq = xdiff * xdiff;
1819     ysq = ydiff * ydiff;
1820     added = xsq + ysq;
1821     xy_add = (double) added;
1822     edge_length = sqrt(xy_add);
1823     return edge_length;
1824 }
1825
1826 double get_angle(double a, double b, double c)
1827 {
1828     double cos_a, i_cos_a;
1829     cos_a = (((b * b) + (c * c)) - (a * a)) / (double) (2.0 * b * c);
1830     i_cos_a = acos(cos_a);
1831     return i_cos_a;
1832 }
1833
1834
1835 Bool is_same_slope(linked_point * a)
1836 {
1837
1838     int abx, bcx, aby, bcy, aa, bb;
1839     linked_point *b;
1840     linked_point *c;
1841
1842     b = a->next;
1843     c = b->next;
1844
1845     // test if slopes are indefinite for both line segments
1846     if (a->x == b->x) {
1847         return b->x == c->x;
1848     } else if (b->x == c->x) {
1849         return False;   // false, as ax/bx is not indefinite
1850     }
1851
1852     abx = a->x - b->x;
1853     bcx = b->x - c->x;
1854     aby = a->y - b->y;
1855     bcy = b->y - c->y;
1856     aa = abx * bcy;
1857     bb = bcx * aby;
1858
1859     return aa == bb;
1860 }
1861
1862 void draw_three_vertices(linked_point * a, Bool triangle)
1863 {
1864
1865     linked_point *b;
1866     linked_point *c;
1867     GLenum drawType;
1868
1869     b = a->next;
1870     c = b->next;
1871
1872     GLfloat vertices[3][2] = {
1873         {a->x, a->y},
1874         {b->x, b->y},
1875         {c->x, c->y}
1876     };
1877
1878     if (triangle) {
1879         drawType = GL_TRIANGLES;
1880     } else {
1881         drawType = GL_LINES;
1882     }
1883
1884     glEnableClientState(GL_VERTEX_ARRAY);
1885     glVertexPointer(2, GL_FLOAT, 0, vertices);
1886     glDrawArrays(drawType, 0, 3);
1887
1888     free(b);  // cut midpoint off from remaining polygon vertex list
1889     a->next = c;
1890 }
1891
1892
1893 Bool is_an_ear(linked_point * a)
1894 {
1895     double edge_ab, edge_bc, edge_ac;
1896     double angle_a, angle_b, angle_c;
1897     double my_pi;
1898     linked_point *b, *c;
1899
1900     b = a->next;
1901     c = b->next;
1902     my_pi = (double) M_PI;
1903
1904     edge_ab = compute_edge_length(a, b);
1905     edge_bc = compute_edge_length(b, c);
1906     edge_ac = compute_edge_length(a, c);
1907     angle_a = get_angle(edge_bc, edge_ab, edge_ac);
1908     angle_b = get_angle(edge_ac, edge_ab, edge_bc);
1909     angle_c = get_angle(edge_ab, edge_ac, edge_bc);
1910
1911     return angle_a < my_pi && angle_b < my_pi && angle_c < my_pi;
1912 }
1913
1914
1915 Bool is_three_point_loop(linked_point * head)
1916 {
1917     return head->x == head->next->next->next->x
1918         && head->y == head->next->next->next->y;
1919 }
1920
1921
1922 void traverse_points_list(linked_point * root)
1923 {
1924     linked_point *head;
1925     head = root;
1926
1927     while (!is_three_point_loop(head)) {
1928         if (is_an_ear(head)) {
1929             draw_three_vertices(head, True);
1930         } else if (is_same_slope(head)) {
1931             draw_three_vertices(head, False);
1932         } else {
1933             head = head->next;
1934         }
1935     }
1936
1937     // handle final three vertices in polygon
1938     if (is_an_ear(head)) {
1939         draw_three_vertices(head, True);
1940     } else if (is_same_slope(head)) {
1941         draw_three_vertices(head, False);
1942     } else {
1943         free(head->next->next);
1944         free(head->next);
1945         free(head);
1946         Assert (False, "traverse_points_list: unknown configuration");
1947     }
1948
1949     free(head->next);
1950     free(head);
1951 }
1952
1953
1954 const struct jwxyz_vtbl gl_vtbl = {
1955   root,
1956   visual,
1957   display_sources_data,
1958
1959   window_background,
1960   draw_arc,
1961   fill_rects,
1962   gc_gcv,
1963   gc_depth,
1964   jwxyz_draw_string,
1965
1966   jwxyz_gl_copy_area,
1967
1968   DrawPoints,
1969   DrawSegments,
1970   CreateGC,
1971   FreeGC,
1972   ClearWindow,
1973   SetClipMask,
1974   SetClipOrigin,
1975   FillPolygon,
1976   DrawLines,
1977   PutImage,
1978   GetSubImage
1979 };
1980
1981 #endif /* JWXYZ_GL -- entire file */