aboutsummaryrefslogtreecommitdiff
path: root/src/share/native/sun/java2d/opengl/OGLRenderer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/share/native/sun/java2d/opengl/OGLRenderer.c')
-rw-r--r--src/share/native/sun/java2d/opengl/OGLRenderer.c485
1 files changed, 484 insertions, 1 deletions
diff --git a/src/share/native/sun/java2d/opengl/OGLRenderer.c b/src/share/native/sun/java2d/opengl/OGLRenderer.c
index 93b1a6e65..ac844b3eb 100644
--- a/src/share/native/sun/java2d/opengl/OGLRenderer.c
+++ b/src/share/native/sun/java2d/opengl/OGLRenderer.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,7 @@
#include <jlong.h>
#include <jni_util.h>
+#include <math.h>
#include "sun_java2d_opengl_OGLRenderer.h"
@@ -326,4 +327,486 @@ OGLRenderer_FillSpans(OGLContext *oglc, jint spanCount, jint *spans)
}
}
+#define FILL_PGRAM(fx11, fy11, dx21, dy21, dx12, dy12) \
+ do { \
+ j2d_glVertex2f(fx11, fy11); \
+ j2d_glVertex2f(fx11 + dx21, fy11 + dy21); \
+ j2d_glVertex2f(fx11 + dx21 + dx12, fy11 + dy21 + dy12); \
+ j2d_glVertex2f(fx11 + dx12, fy11 + dy12); \
+ } while (0)
+
+void
+OGLRenderer_FillParallelogram(OGLContext *oglc,
+ jfloat fx11, jfloat fy11,
+ jfloat dx21, jfloat dy21,
+ jfloat dx12, jfloat dy12)
+{
+ J2dTraceLn6(J2D_TRACE_INFO,
+ "OGLRenderer_FillParallelogram "
+ "(x=%6.2f y=%6.2f "
+ "dx1=%6.2f dy1=%6.2f "
+ "dx2=%6.2f dy2=%6.2f)",
+ fx11, fy11,
+ dx21, dy21,
+ dx12, dy12);
+
+ RETURN_IF_NULL(oglc);
+
+ CHECK_PREVIOUS_OP(GL_QUADS);
+
+ FILL_PGRAM(fx11, fy11, dx21, dy21, dx12, dy12);
+}
+
+void
+OGLRenderer_DrawParallelogram(OGLContext *oglc,
+ jfloat fx11, jfloat fy11,
+ jfloat dx21, jfloat dy21,
+ jfloat dx12, jfloat dy12,
+ jfloat lwr21, jfloat lwr12)
+{
+ // dx,dy for line width in the "21" and "12" directions.
+ jfloat ldx21 = dx21 * lwr21;
+ jfloat ldy21 = dy21 * lwr21;
+ jfloat ldx12 = dx12 * lwr12;
+ jfloat ldy12 = dy12 * lwr12;
+
+ // calculate origin of the outer parallelogram
+ jfloat ox11 = fx11 - (ldx21 + ldx12) / 2.0f;
+ jfloat oy11 = fy11 - (ldy21 + ldy12) / 2.0f;
+
+ J2dTraceLn8(J2D_TRACE_INFO,
+ "OGLRenderer_DrawParallelogram "
+ "(x=%6.2f y=%6.2f "
+ "dx1=%6.2f dy1=%6.2f lwr1=%6.2f "
+ "dx2=%6.2f dy2=%6.2f lwr2=%6.2f)",
+ fx11, fy11,
+ dx21, dy21, lwr21,
+ dx12, dy12, lwr12);
+
+ RETURN_IF_NULL(oglc);
+
+ CHECK_PREVIOUS_OP(GL_QUADS);
+
+ // Only need to generate 4 quads if the interior still
+ // has a hole in it (i.e. if the line width ratio was
+ // less than 1.0)
+ if (lwr21 < 1.0f && lwr12 < 1.0f) {
+ // Note: "TOP", "BOTTOM", "LEFT" and "RIGHT" here are
+ // relative to whether the dxNN variables are positive
+ // and negative. The math works fine regardless of
+ // their signs, but for conceptual simplicity the
+ // comments will refer to the sides as if the dxNN
+ // were all positive. "TOP" and "BOTTOM" segments
+ // are defined by the dxy21 deltas. "LEFT" and "RIGHT"
+ // segments are defined by the dxy12 deltas.
+
+ // Each segment includes its starting corner and comes
+ // to just short of the following corner. Thus, each
+ // corner is included just once and the only lengths
+ // needed are the original parallelogram delta lengths
+ // and the "line width deltas". The sides will cover
+ // the following relative territories:
+ //
+ // T T T T T R
+ // L R
+ // L R
+ // L R
+ // L R
+ // L B B B B B
+
+ // TOP segment, to left side of RIGHT edge
+ // "width" of original pgram, "height" of hor. line size
+ fx11 = ox11;
+ fy11 = oy11;
+ FILL_PGRAM(fx11, fy11, dx21, dy21, ldx12, ldy12);
+
+ // RIGHT segment, to top of BOTTOM edge
+ // "width" of vert. line size , "height" of original pgram
+ fx11 = ox11 + dx21;
+ fy11 = oy11 + dy21;
+ FILL_PGRAM(fx11, fy11, ldx21, ldy21, dx12, dy12);
+
+ // BOTTOM segment, from right side of LEFT edge
+ // "width" of original pgram, "height" of hor. line size
+ fx11 = ox11 + dx12 + ldx21;
+ fy11 = oy11 + dy12 + ldy21;
+ FILL_PGRAM(fx11, fy11, dx21, dy21, ldx12, ldy12);
+
+ // LEFT segment, from bottom of TOP edge
+ // "width" of vert. line size , "height" of inner pgram
+ fx11 = ox11 + ldx12;
+ fy11 = oy11 + ldy12;
+ FILL_PGRAM(fx11, fy11, ldx21, ldy21, dx12, dy12);
+ } else {
+ // The line width ratios were large enough to consume
+ // the entire hole in the middle of the parallelogram
+ // so we can just issue one large quad for the outer
+ // parallelogram.
+ dx21 += ldx21;
+ dy21 += ldy21;
+ dx12 += ldx12;
+ dy12 += ldy12;
+ FILL_PGRAM(ox11, oy11, dx21, dy21, dx12, dy12);
+ }
+}
+
+static GLhandleARB aaPgramProgram = 0;
+
+/*
+ * This shader fills the space between an outer and inner parallelogram.
+ * It can be used to draw an outline by specifying both inner and outer
+ * values. It fills pixels by estimating what portion falls inside the
+ * outer shape, and subtracting an estimate of what portion falls inside
+ * the inner shape. Specifying both inner and outer values produces a
+ * standard "wide outline". Specifying an inner shape that falls far
+ * outside the outer shape allows the same shader to fill the outer
+ * shape entirely since pixels that fall within the outer shape are never
+ * inside the inner shape and so they are filled based solely on their
+ * coverage of the outer shape.
+ *
+ * The setup code renders this shader over the bounds of the outer
+ * shape (or the only shape in the case of a fill operation) and
+ * sets the texture 0 coordinates so that 0,0=>0,1=>1,1=>1,0 in those
+ * texture coordinates map to the four corners of the parallelogram.
+ * Similarly the texture 1 coordinates map the inner shape to the
+ * unit square as well, but in a different coordinate system.
+ *
+ * When viewed in the texture coordinate systems the parallelograms
+ * we are filling are unit squares, but the pixels have then become
+ * tiny parallelograms themselves. Both of the texture coordinate
+ * systems are affine transforms so the rate of change in X and Y
+ * of the texture coordinates are essentially constants and happen
+ * to correspond to the size and direction of the slanted sides of
+ * the distorted pixels relative to the "square mapped" boundary
+ * of the parallelograms.
+ *
+ * The shader uses the dFdx() and dFdy() functions to measure the "rate
+ * of change" of these texture coordinates and thus gets an accurate
+ * measure of the size and shape of a pixel relative to the two
+ * parallelograms. It then uses the bounds of the size and shape
+ * of a pixel to intersect with the unit square to estimate the
+ * coverage of the pixel. Unfortunately, without a lot more work
+ * to calculate the exact area of intersection between a unit
+ * square (the original parallelogram) and a parallelogram (the
+ * distorted pixel), this shader only approximates the pixel
+ * coverage, but emperically the estimate is very useful and
+ * produces visually pleasing results, if not theoretically accurate.
+ */
+static const char *aaPgramShaderSource =
+ "void main() {"
+ // Calculate the vectors for the "legs" of the pixel parallelogram
+ // for the outer parallelogram.
+ " vec2 oleg1 = dFdx(gl_TexCoord[0].st);"
+ " vec2 oleg2 = dFdy(gl_TexCoord[0].st);"
+ // Calculate the bounds of the distorted pixel parallelogram.
+ " vec2 corner = gl_TexCoord[0].st - (oleg1+oleg2)/2.0;"
+ " vec2 omin = min(corner, corner+oleg1);"
+ " omin = min(omin, corner+oleg2);"
+ " omin = min(omin, corner+oleg1+oleg2);"
+ " vec2 omax = max(corner, corner+oleg1);"
+ " omax = max(omax, corner+oleg2);"
+ " omax = max(omax, corner+oleg1+oleg2);"
+ // Calculate the vectors for the "legs" of the pixel parallelogram
+ // for the inner parallelogram.
+ " vec2 ileg1 = dFdx(gl_TexCoord[1].st);"
+ " vec2 ileg2 = dFdy(gl_TexCoord[1].st);"
+ // Calculate the bounds of the distorted pixel parallelogram.
+ " corner = gl_TexCoord[1].st - (ileg1+ileg2)/2.0;"
+ " vec2 imin = min(corner, corner+ileg1);"
+ " imin = min(imin, corner+ileg2);"
+ " imin = min(imin, corner+ileg1+ileg2);"
+ " vec2 imax = max(corner, corner+ileg1);"
+ " imax = max(imax, corner+ileg2);"
+ " imax = max(imax, corner+ileg1+ileg2);"
+ // Clamp the bounds of the parallelograms to the unit square to
+ // estimate the intersection of the pixel parallelogram with
+ // the unit square. The ratio of the 2 rectangle areas is a
+ // reasonable estimate of the proportion of coverage.
+ " vec2 o1 = clamp(omin, 0.0, 1.0);"
+ " vec2 o2 = clamp(omax, 0.0, 1.0);"
+ " float oint = (o2.y-o1.y)*(o2.x-o1.x);"
+ " float oarea = (omax.y-omin.y)*(omax.x-omin.x);"
+ " vec2 i1 = clamp(imin, 0.0, 1.0);"
+ " vec2 i2 = clamp(imax, 0.0, 1.0);"
+ " float iint = (i2.y-i1.y)*(i2.x-i1.x);"
+ " float iarea = (imax.y-imin.y)*(imax.x-imin.x);"
+ // Proportion of pixel in outer shape minus the proportion
+ // of pixel in the inner shape == the coverage of the pixel
+ // in the area between the two.
+ " float coverage = oint/oarea - iint / iarea;"
+ " gl_FragColor = gl_Color * coverage;"
+ "}";
+
+#define ADJUST_PGRAM(V1, DV, V2) \
+ do { \
+ if ((DV) >= 0) { \
+ (V2) += (DV); \
+ } else { \
+ (V1) += (DV); \
+ } \
+ } while (0)
+
+// Invert the following transform:
+// DeltaT(0, 0) == (0, 0)
+// DeltaT(1, 0) == (DX1, DY1)
+// DeltaT(0, 1) == (DX2, DY2)
+// DeltaT(1, 1) == (DX1+DX2, DY1+DY2)
+// TM00 = DX1, TM01 = DX2, (TM02 = X11)
+// TM10 = DY1, TM11 = DY2, (TM12 = Y11)
+// Determinant = TM00*TM11 - TM01*TM10
+// = DX1*DY2 - DX2*DY1
+// Inverse is:
+// IM00 = TM11/det, IM01 = -TM01/det
+// IM10 = -TM10/det, IM11 = TM00/det
+// IM02 = (TM01 * TM12 - TM11 * TM02) / det,
+// IM12 = (TM10 * TM02 - TM00 * TM12) / det,
+
+#define DECLARE_MATRIX(MAT) \
+ jfloat MAT ## 00, MAT ## 01, MAT ## 02, MAT ## 10, MAT ## 11, MAT ## 12
+
+#define GET_INVERTED_MATRIX(MAT, X11, Y11, DX1, DY1, DX2, DY2, RET_CODE) \
+ do { \
+ jfloat det = DX1*DY2 - DX2*DY1; \
+ if (det == 0) { \
+ RET_CODE; \
+ } \
+ MAT ## 00 = DY2/det; \
+ MAT ## 01 = -DX2/det; \
+ MAT ## 10 = -DY1/det; \
+ MAT ## 11 = DX1/det; \
+ MAT ## 02 = (DX2 * Y11 - DY2 * X11) / det; \
+ MAT ## 12 = (DY1 * X11 - DX1 * Y11) / det; \
+ } while (0)
+
+#define TRANSFORM(MAT, TX, TY, X, Y) \
+ do { \
+ TX = (X) * MAT ## 00 + (Y) * MAT ## 01 + MAT ## 02; \
+ TY = (X) * MAT ## 10 + (Y) * MAT ## 11 + MAT ## 12; \
+ } while (0)
+
+void
+OGLRenderer_FillAAParallelogram(OGLContext *oglc, OGLSDOps *dstOps,
+ jfloat fx11, jfloat fy11,
+ jfloat dx21, jfloat dy21,
+ jfloat dx12, jfloat dy12)
+{
+ DECLARE_MATRIX(om);
+ // parameters for parallelogram bounding box
+ jfloat bx11, by11, bx22, by22;
+ // parameters for uv texture coordinates of parallelogram corners
+ jfloat u11, v11, u12, v12, u21, v21, u22, v22;
+
+ J2dTraceLn6(J2D_TRACE_INFO,
+ "OGLRenderer_FillAAParallelogram "
+ "(x=%6.2f y=%6.2f "
+ "dx1=%6.2f dy1=%6.2f "
+ "dx2=%6.2f dy2=%6.2f)",
+ fx11, fy11,
+ dx21, dy21,
+ dx12, dy12);
+
+ RETURN_IF_NULL(oglc);
+ RETURN_IF_NULL(dstOps);
+
+ GET_INVERTED_MATRIX(om, fx11, fy11, dx21, dy21, dx12, dy12,
+ return);
+
+ CHECK_PREVIOUS_OP(OGL_STATE_PGRAM_OP);
+
+ bx11 = bx22 = fx11;
+ by11 = by22 = fy11;
+ ADJUST_PGRAM(bx11, dx21, bx22);
+ ADJUST_PGRAM(by11, dy21, by22);
+ ADJUST_PGRAM(bx11, dx12, bx22);
+ ADJUST_PGRAM(by11, dy12, by22);
+ bx11 = (jfloat) floor(bx11);
+ by11 = (jfloat) floor(by11);
+ bx22 = (jfloat) ceil(bx22);
+ by22 = (jfloat) ceil(by22);
+
+ TRANSFORM(om, u11, v11, bx11, by11);
+ TRANSFORM(om, u21, v21, bx22, by11);
+ TRANSFORM(om, u12, v12, bx11, by22);
+ TRANSFORM(om, u22, v22, bx22, by22);
+
+ j2d_glBegin(GL_QUADS);
+ j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u11, v11);
+ j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 5.f, 5.f);
+ j2d_glVertex2f(bx11, by11);
+ j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u21, v21);
+ j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 6.f, 5.f);
+ j2d_glVertex2f(bx22, by11);
+ j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u22, v22);
+ j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 6.f, 6.f);
+ j2d_glVertex2f(bx22, by22);
+ j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u12, v12);
+ j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 5.f, 6.f);
+ j2d_glVertex2f(bx11, by22);
+ j2d_glEnd();
+}
+
+void
+OGLRenderer_FillAAParallelogramInnerOuter(OGLContext *oglc, OGLSDOps *dstOps,
+ jfloat ox11, jfloat oy11,
+ jfloat ox21, jfloat oy21,
+ jfloat ox12, jfloat oy12,
+ jfloat ix11, jfloat iy11,
+ jfloat ix21, jfloat iy21,
+ jfloat ix12, jfloat iy12)
+{
+ DECLARE_MATRIX(om);
+ DECLARE_MATRIX(im);
+ // parameters for parallelogram bounding box
+ jfloat bx11, by11, bx22, by22;
+ // parameters for uv texture coordinates of outer parallelogram corners
+ jfloat ou11, ov11, ou12, ov12, ou21, ov21, ou22, ov22;
+ // parameters for uv texture coordinates of inner parallelogram corners
+ jfloat iu11, iv11, iu12, iv12, iu21, iv21, iu22, iv22;
+
+ RETURN_IF_NULL(oglc);
+ RETURN_IF_NULL(dstOps);
+
+ GET_INVERTED_MATRIX(im, ix11, iy11, ix21, iy21, ix12, iy12,
+ // inner parallelogram is degenerate
+ // therefore it encloses no area
+ // fill outer
+ OGLRenderer_FillAAParallelogram(oglc, dstOps,
+ ox11, oy11,
+ ox21, oy21,
+ ox12, oy12);
+ return);
+ GET_INVERTED_MATRIX(om, ox11, oy11, ox21, oy21, ox12, oy12,
+ return);
+
+ CHECK_PREVIOUS_OP(OGL_STATE_PGRAM_OP);
+
+ bx11 = bx22 = ox11;
+ by11 = by22 = oy11;
+ ADJUST_PGRAM(bx11, ox21, bx22);
+ ADJUST_PGRAM(by11, oy21, by22);
+ ADJUST_PGRAM(bx11, ox12, bx22);
+ ADJUST_PGRAM(by11, oy12, by22);
+ bx11 = (jfloat) floor(bx11);
+ by11 = (jfloat) floor(by11);
+ bx22 = (jfloat) ceil(bx22);
+ by22 = (jfloat) ceil(by22);
+
+ TRANSFORM(om, ou11, ov11, bx11, by11);
+ TRANSFORM(om, ou21, ov21, bx22, by11);
+ TRANSFORM(om, ou12, ov12, bx11, by22);
+ TRANSFORM(om, ou22, ov22, bx22, by22);
+
+ TRANSFORM(im, iu11, iv11, bx11, by11);
+ TRANSFORM(im, iu21, iv21, bx22, by11);
+ TRANSFORM(im, iu12, iv12, bx11, by22);
+ TRANSFORM(im, iu22, iv22, bx22, by22);
+
+ j2d_glBegin(GL_QUADS);
+ j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, ou11, ov11);
+ j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, iu11, iv11);
+ j2d_glVertex2f(bx11, by11);
+ j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, ou21, ov21);
+ j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, iu21, iv21);
+ j2d_glVertex2f(bx22, by11);
+ j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, ou22, ov22);
+ j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, iu22, iv22);
+ j2d_glVertex2f(bx22, by22);
+ j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, ou12, ov12);
+ j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, iu12, iv12);
+ j2d_glVertex2f(bx11, by22);
+ j2d_glEnd();
+}
+
+void
+OGLRenderer_DrawAAParallelogram(OGLContext *oglc, OGLSDOps *dstOps,
+ jfloat fx11, jfloat fy11,
+ jfloat dx21, jfloat dy21,
+ jfloat dx12, jfloat dy12,
+ jfloat lwr21, jfloat lwr12)
+{
+ // dx,dy for line width in the "21" and "12" directions.
+ jfloat ldx21, ldy21, ldx12, ldy12;
+ // parameters for "outer" parallelogram
+ jfloat ofx11, ofy11, odx21, ody21, odx12, ody12;
+ // parameters for "inner" parallelogram
+ jfloat ifx11, ify11, idx21, idy21, idx12, idy12;
+
+ J2dTraceLn8(J2D_TRACE_INFO,
+ "OGLRenderer_DrawAAParallelogram "
+ "(x=%6.2f y=%6.2f "
+ "dx1=%6.2f dy1=%6.2f lwr1=%6.2f "
+ "dx2=%6.2f dy2=%6.2f lwr2=%6.2f)",
+ fx11, fy11,
+ dx21, dy21, lwr21,
+ dx12, dy12, lwr12);
+
+ RETURN_IF_NULL(oglc);
+ RETURN_IF_NULL(dstOps);
+
+ // calculate true dx,dy for line widths from the "line width ratios"
+ ldx21 = dx21 * lwr21;
+ ldy21 = dy21 * lwr21;
+ ldx12 = dx12 * lwr12;
+ ldy12 = dy12 * lwr12;
+
+ // calculate coordinates of the outer parallelogram
+ ofx11 = fx11 - (ldx21 + ldx12) / 2.0f;
+ ofy11 = fy11 - (ldy21 + ldy12) / 2.0f;
+ odx21 = dx21 + ldx21;
+ ody21 = dy21 + ldy21;
+ odx12 = dx12 + ldx12;
+ ody12 = dy12 + ldy12;
+
+ // Only process the inner parallelogram if the line width ratio
+ // did not consume the entire interior of the parallelogram
+ // (i.e. if the width ratio was less than 1.0)
+ if (lwr21 < 1.0f && lwr12 < 1.0f) {
+ // calculate coordinates of the inner parallelogram
+ ifx11 = fx11 + (ldx21 + ldx12) / 2.0f;
+ ify11 = fy11 + (ldy21 + ldy12) / 2.0f;
+ idx21 = dx21 - ldx21;
+ idy21 = dy21 - ldy21;
+ idx12 = dx12 - ldx12;
+ idy12 = dy12 - ldy12;
+
+ OGLRenderer_FillAAParallelogramInnerOuter(oglc, dstOps,
+ ofx11, ofy11,
+ odx21, ody21,
+ odx12, ody12,
+ ifx11, ify11,
+ idx21, idy21,
+ idx12, idy12);
+ } else {
+ OGLRenderer_FillAAParallelogram(oglc, dstOps,
+ ofx11, ofy11,
+ odx21, ody21,
+ odx12, ody12);
+ }
+}
+
+void
+OGLRenderer_EnableAAParallelogramProgram()
+{
+ J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_EnableAAParallelogramProgram");
+
+ if (aaPgramProgram == 0) {
+ aaPgramProgram = OGLContext_CreateFragmentProgram(aaPgramShaderSource);
+ if (aaPgramProgram == 0) {
+ J2dRlsTraceLn(J2D_TRACE_ERROR,
+ "OGLRenderer_EnableAAParallelogramProgram: "
+ "error creating program");
+ return;
+ }
+ }
+ j2d_glUseProgramObjectARB(aaPgramProgram);
+}
+
+void
+OGLRenderer_DisableAAParallelogramProgram()
+{
+ J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_DisableAAParallelogramProgram");
+
+ j2d_glUseProgramObjectARB(0);
+}
+
#endif /* !HEADLESS */