summaryrefslogtreecommitdiffstats
path: root/jwxyz/jwxyz-gl.c
diff options
context:
space:
mode:
Diffstat (limited to 'jwxyz/jwxyz-gl.c')
-rw-r--r--jwxyz/jwxyz-gl.c273
1 files changed, 157 insertions, 116 deletions
diff --git a/jwxyz/jwxyz-gl.c b/jwxyz/jwxyz-gl.c
index 369d16f..f1c13da 100644
--- a/jwxyz/jwxyz-gl.c
+++ b/jwxyz/jwxyz-gl.c
@@ -544,7 +544,7 @@ visual (Display *dpy)
*/
static void *
-enqueue (Display *dpy, Drawable d, GC gc, int mode, size_t count,
+enqueue (Display *dpy, Drawable d, GC gc, GLenum mode, size_t count,
unsigned long pixel)
{
if (dpy->queue_size &&
@@ -947,7 +947,8 @@ jwxyz_gl_copy_area_read_tex_image (Display *dpy, unsigned src_height,
}
void
-jwxyz_gl_copy_area_write_tex_image (Display *dpy, GC gc, int src_x, int src_y,
+jwxyz_gl_copy_area_write_tex_image (Display *dpy, GC gc,
+ int src_x, int src_y, int src_depth,
unsigned int width, unsigned int height,
int dst_x, int dst_y)
{
@@ -964,7 +965,7 @@ jwxyz_gl_copy_area_write_tex_image (Display *dpy, GC gc, int src_x, int src_y,
glBindTexture (dpy->gl_texture_target, dpy->textures[texture_rgba]);
jwxyz_gl_draw_image (dpy, gc, dpy->gl_texture_target, tex_w, tex_h,
- 0, 0, gc->depth, width, height, dst_x, dst_y, False);
+ 0, 0, src_depth, width, height, dst_x, dst_y, False);
clear_texture (dpy);
}
@@ -1291,10 +1292,32 @@ FillPolygon (Display *dpy, Drawable d, GC gc,
#define degrees(RAD) ((RAD) * 180.0 / M_PI)
static void
-arc_xy(GLfloat *p, double cx, double cy, double w2, double h2, double theta)
+arc_xy (GLfloat *p, GLfloat cx, GLfloat cy, GLfloat w2, GLfloat h2,
+ GLfloat theta)
{
- p[0] = cos(theta) * w2 + cx;
- p[1] = -sin(theta) * h2 + cy;
+ p[0] = cx + cosf(theta) * w2;
+ p[1] = cy - sinf(theta) * h2;
+}
+
+static void
+arc_xy2 (GLfloat *p, GLfloat cx, GLfloat cy, GLfloat w2, GLfloat h2,
+ GLfloat theta, GLfloat gglw)
+{
+ // The inner/outer contour of the stroke of an ellipse is not itself an
+ // ellipse.
+
+ GLfloat ct = cosf(theta), st = sinf(theta);
+
+ GLfloat w2st = w2 * st, h2ct = h2 * ct;
+ GLfloat w2ct = w2 * ct, h2st = h2 * st;
+
+ GLfloat d = gglw / sqrtf(w2st * w2st + h2ct * h2ct);
+ GLfloat dh2ct = d * h2ct, dw2st = d * w2st;
+
+ p[0] = cx + w2ct + dh2ct;
+ p[1] = cy - (h2st + dw2st);
+ p[2] = cx + w2ct - dh2ct;
+ p[3] = cy - (h2st - dw2st);
}
static unsigned
@@ -1306,48 +1329,17 @@ mod_neg(int a, unsigned b)
return a < 0 ? (b - 1) - (-(a + 1) % b) : a % b;
}
-/* TODO: Fill in arcs with line width > 1 */
static int
draw_arc (Display *dpy, Drawable d, GC gc, int x, int y,
unsigned int width, unsigned int height,
int angle1, int angle2, Bool fill_p)
{
- int gglw = gc->gcv.line_width;
-
- if (fill_p || gglw <= 1) {
- draw_arc_gl (dpy, d, gc, x, y, width, height, angle1, angle2, fill_p);
- }
- else {
- int w1, w2, h1, h2, gglwh;
- w1 = width + gglw;
- h1 = height + gglw;
- h2 = height - gglw;
- w2 = width - gglw;
- gglwh = gglw / 2;
- int x1 = x - gglwh;
- int x2 = x + gglwh;
- int y1 = y - gglwh;
- int y2 = y + gglwh;
- //draw_arc_gl (dpy, d, gc, x, y, width, height, angle1, angle2, fill_p);
- draw_arc_gl (dpy, d, gc, x1, y1, w1, h1, angle1, angle2, fill_p);
- draw_arc_gl (dpy, d, gc, x2, y2, w2, h2, angle1, angle2, fill_p);
- }
- return 0;
-}
-
-
-int
-draw_arc_gl (Display *dpy, Drawable d, GC gc, int x, int y,
- unsigned int width, unsigned int height,
- int angle1, int angle2, Bool fill_p)
-{
- set_fg_gc(dpy, d, gc);
-
- /* Let's say the number of line segments needed to make a convincing circle is
- 4*sqrt(radius). (But these arcs aren't necessarily circular arcs...) */
+ /* Let's say the number of line segments needed to make a convincing circle
+ is 4*sqrt(radius). (But these arcs aren't necessarily circular arcs...)
+ */
- double w2 = width * 0.5f, h2 = height * 0.5f;
- double a, b; /* Semi-major/minor axes. */
+ GLfloat w2 = width * 0.5f, h2 = height * 0.5f;
+ GLfloat a, b; /* Semi-major/minor axes. */
if(w2 > h2) {
a = w2;
b = h2;
@@ -1355,30 +1347,30 @@ draw_arc_gl (Display *dpy, Drawable d, GC gc, int x, int y,
a = h2;
b = w2;
}
-
- const double two_pi = 2 * M_PI;
- double amb = a - b, apb = a + b;
- double h = (amb * amb) / (apb * apb);
- // TODO: Math cleanup.
- double C_approx = M_PI * apb * (1 + 3 * h / (10 + sqrtf(4 - 3 * h)));
- double segments_f = 4 * sqrtf(C_approx / (2 * M_PI));
+ const GLfloat tau = 2 * M_PI;
+
+ GLfloat amb = a - b, apb = a + b;
+ GLfloat h = (amb * amb) / (apb * apb);
+ GLfloat D_approx = apb * (1 + 3 * h / (10 + sqrtf(4 - 3 * h)));
+ // From Ramanujan, "Modular Equations and Approximations to π".
+ // double C_approx = D_approx * M_PI;
+ GLfloat segments_f = sqrtf(8 * D_approx);
// TODO: Explain how drawing works what with the points of overlapping arcs
// matching up.
-
-#if 1
+
unsigned segments_360 = segments_f;
-
+
/* TODO: angle2 == 0. This is a tilted square with CapSquare. */
/* TODO: color, thick lines, CapNotLast for thin lines */
/* TODO: Transformations. */
- double segment_angle = two_pi / segments_360;
+ GLfloat segment_angle = tau / segments_360;
const unsigned deg64 = 360 * 64;
- const double rad_from_deg64 = two_pi / deg64;
-
+ const GLfloat rad_from_deg64 = tau / deg64;
+
if (angle2 < 0) {
angle1 += angle2;
angle2 = -angle2;
@@ -1388,79 +1380,128 @@ draw_arc_gl (Display *dpy, Drawable d, GC gc, int x, int y,
if (angle2 > deg64)
angle2 = deg64; // TODO: Handle circles special.
-
- double
+
+ GLfloat
angle1_f = angle1 * rad_from_deg64,
angle2_f = angle2 * rad_from_deg64;
-
- if (angle2_f > two_pi) // TODO: Move this up.
- angle2_f = two_pi;
-
- double segment1_angle_part = fmodf(angle1_f, segment_angle);
-
- unsigned segment1 = ((angle1_f - segment1_angle_part) / segment_angle) + 1.5;
- double angle_2r = angle2_f - segment1_angle_part;
+ if (angle2_f > tau) // TODO: Move this up.
+ angle2_f = tau;
+
+ GLfloat segment0_angle_part = fmodf(angle1_f, segment_angle);
+
+ unsigned segment0 = ((angle1_f - segment0_angle_part) / segment_angle) + 1.5;
+
+ GLfloat angle_2r = angle2_f - segment0_angle_part;
unsigned segments = angle_2r / segment_angle;
-
+
GLfloat cx = x + w2, cy = y + h2;
- GLfloat *data = malloc((segments + 3) * sizeof(GLfloat) * 2); // TODO: Check result.
-
- GLfloat *data_ptr = data;
+ /* TODO: It would probably be better for vertices at the corners of the
+ elliptical sector/arc to be the intersection between a ray extending from
+ the ellipse center along one of the specified angles and one of the line
+ segments following the outline of the 360-degree ellipse, rather than
+ what it is now.
+ */
+
if (fill_p) {
- data_ptr[0] = cx;
- data_ptr[1] = cy;
+ GLfloat *data = enqueue (dpy, d, gc, GL_TRIANGLE_STRIP, segments + 5,
+ gc->gcv.foreground);
+ GLfloat *data_ptr = data;
+
+ unsigned segment1 = segment0 + segments / 2;
+ unsigned ds = segment1 - segment0 + 1;
+ unsigned ds2 = ds / 2;
+
+ if (ds & 1) {
+ arc_xy (data_ptr, cx, cy, w2, h2, (segment0 + ds2) * segment_angle);
+ data_ptr += 2;
+ }
+
+ unsigned s = ds2;
+ while (s) {
+ --s;
+ arc_xy (data_ptr, cx, cy, w2, h2, (segment0 + s) * segment_angle);
+ arc_xy (data_ptr + 2, cx, cy, w2, h2,
+ (segment1 - s) * segment_angle);
+ data_ptr += 4;
+ }
+
+ arc_xy (data_ptr, cx, cy, w2, h2, angle1_f);
+ data_ptr[2] = cx;
+ data_ptr[3] = cy;
+ data_ptr[4] = cx;
+ data_ptr[5] = cy;
+ arc_xy (data_ptr + 6, cx, cy, w2, h2, angle1_f + angle2_f);
+ data_ptr += 8;
+
+ unsigned segment2 = segment0 + segments;
+ ds = segment2 - segment1;
+ ds2 = ds / 2;
+
+ for (s = 0; s != ds2; ++s) {
+ arc_xy (data_ptr, cx, cy, w2, h2, (segment1 + s) * segment_angle);
+ arc_xy (data_ptr + 2, cx, cy, w2, h2,
+ (segment2 - s - 1) * segment_angle);
+ data_ptr += 4;
+ }
+
+ if (ds & 1) {
+ arc_xy (data_ptr, cx, cy, w2, h2, (segment1 + ds2) * segment_angle);
+ data_ptr += 2;
+ }
+
+ finish_triangle_strip (dpy, data);
+ } else if (!gc->gcv.line_width) {
+ set_fg_gc(dpy, d, gc);
+
+ GLfloat *data = malloc((segments + 2) * sizeof(GLfloat) * 2); // TODO: Check result.
+ GLfloat *data_ptr = data;
+
+ arc_xy (data_ptr, cx, cy, w2, h2, angle1_f);
data_ptr += 2;
- }
-
- arc_xy (data_ptr, cx, cy, w2, h2, angle1_f);
- data_ptr += 2;
-
- for (unsigned s = 0; s != segments; ++s) {
- // TODO: Make sure values of theta for the following arc_xy call are between
- // angle1_f and angle1_f + angle2_f.
- arc_xy (data_ptr, cx, cy, w2, h2, (segment1 + s) * segment_angle);
+
+ for (unsigned s = 0; s != segments; ++s) {
+ // TODO: Make sure values of theta for the following arc_xy call are between
+ // angle1_f and angle1_f + angle2_f.
+ arc_xy (data_ptr, cx, cy, w2, h2, (segment0 + s) * segment_angle);
+ data_ptr += 2;
+ }
+
+ arc_xy (data_ptr, cx, cy, w2, h2, angle1_f + angle2_f);
data_ptr += 2;
- }
-
- arc_xy (data_ptr, cx, cy, w2, h2, angle1_f + angle2_f);
- data_ptr += 2;
- glDisableClientState (GL_TEXTURE_COORD_ARRAY);
- glEnableClientState (GL_VERTEX_ARRAY);
-
- vertex_pointer (dpy, GL_FLOAT, 0, data);
- glDrawArrays (fill_p ? GL_TRIANGLE_FAN : GL_LINE_STRIP,
- 0,
- (GLsizei)((data_ptr - data) / 2));
+ glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+ glEnableClientState (GL_VERTEX_ARRAY);
- free(data);
-
-#endif
-
-#if 0
- unsigned segments = segments_f * (fabs(angle2) / (360 * 64));
-
- glBegin (fill_p ? GL_TRIANGLE_FAN : GL_LINE_STRIP);
-
- if (fill_p /* && gc->gcv.arc_mode == ArcPieSlice */)
- glVertex2f (cx, cy);
-
- /* TODO: This should fix the middle points of the arc so that the starting and ending points are OK. */
-
- float to_radians = 2 * M_PI / (360 * 64);
- float theta = angle1 * to_radians, d_theta = angle2 * to_radians / segments;
-
- for (unsigned s = 0; s != segments + 1; ++s) /* TODO: This is the right number of segments, yes? */
- {
- glVertex2f(cos(theta) * w2 + cx, -sin(theta) * h2 + cy);
- theta += d_theta;
+ vertex_pointer (dpy, GL_FLOAT, 0, data);
+ glDrawArrays (fill_p ? GL_TRIANGLE_FAN : GL_LINE_STRIP,
+ 0,
+ (GLsizei)((data_ptr - data) / 2));
+
+ free(data);
+ } else {
+ GLfloat gglw = gc->gcv.line_width * 0.5f;
+
+ GLfloat *data = enqueue (dpy, d, gc, GL_TRIANGLE_STRIP, 2 * segments + 4,
+ gc->gcv.foreground);
+ GLfloat *data_ptr = data;
+
+ arc_xy2 (data_ptr, cx, cy, w2, h2, angle1_f, gglw);
+ data_ptr += 4;
+
+ for (unsigned s = 0; s != segments; ++s) {
+ arc_xy2 (data_ptr, cx, cy, w2, h2, (segment0 + s) * segment_angle,
+ gglw);
+ data_ptr += 4;
+ }
+
+ arc_xy2 (data_ptr, cx, cy, w2, h2, angle1_f + angle2_f, gglw);
+ data_ptr += 4;
+
+ finish_triangle_strip (dpy, data);
}
-
- glEnd ();
-#endif
-
+
return 0;
}