alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (OGLRenderer.c)

This example Java source code file (OGLRenderer.c) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

adjust_pgram, check_previous_op, declare_matrix, fill_pgram, get_inverted_matrix, glfloat, j2dtraceln, mat, oglrenderer_drawpoly, oglrenderer_fillaaparallelogram, oglsdops, return_if_null, transform

The OGLRenderer.c Java example source code

/*
 * Copyright (c) 2003, 2008, Oracle and/or its affiliates. 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
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

#ifndef HEADLESS

#include <jlong.h>
#include <jni_util.h>
#include <math.h>

#include "sun_java2d_opengl_OGLRenderer.h"

#include "OGLRenderer.h"
#include "OGLRenderQueue.h"
#include "OGLSurfaceData.h"

/**
 * Note: Some of the methods in this file apply a "magic number"
 * translation to line segments.  The OpenGL specification lays out the
 * "diamond exit rule" for line rasterization, but it is loose enough to
 * allow for a wide range of line rendering hardware.  (It appears that
 * some hardware, such as the Nvidia GeForce2 series, does not even meet
 * the spec in all cases.)  As such it is difficult to find a mapping
 * between the Java2D and OpenGL line specs that works consistently across
 * all hardware combinations.
 *
 * Therefore the "magic numbers" you see here have been empirically derived
 * after testing on a variety of graphics hardware in order to find some
 * reasonable middle ground between the two specifications.  The general
 * approach is to apply a fractional translation to vertices so that they
 * hit pixel centers and therefore touch the same pixels as in our other
 * pipelines.  Emphasis was placed on finding values so that OGL lines with
 * a slope of +/- 1 hit all the same pixels as our other (software) loops.
 * The stepping in other diagonal lines rendered with OGL may deviate
 * slightly from those rendered with our software loops, but the most
 * important thing is that these magic numbers ensure that all OGL lines
 * hit the same endpoints as our software loops.
 *
 * If you find it necessary to change any of these magic numbers in the
 * future, just be sure that you test the changes across a variety of
 * hardware to ensure consistent rendering everywhere.
 */

void
OGLRenderer_DrawLine(OGLContext *oglc, jint x1, jint y1, jint x2, jint y2)
{
    J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_DrawLine");

    RETURN_IF_NULL(oglc);

    CHECK_PREVIOUS_OP(GL_LINES);

    if (y1 == y2) {
        // horizontal
        GLfloat fx1 = (GLfloat)x1;
        GLfloat fx2 = (GLfloat)x2;
        GLfloat fy  = ((GLfloat)y1) + 0.2f;

        if (x1 > x2) {
            GLfloat t = fx1; fx1 = fx2; fx2 = t;
        }

        j2d_glVertex2f(fx1+0.2f, fy);
        j2d_glVertex2f(fx2+1.2f, fy);
    } else if (x1 == x2) {
        // vertical
        GLfloat fx  = ((GLfloat)x1) + 0.2f;
        GLfloat fy1 = (GLfloat)y1;
        GLfloat fy2 = (GLfloat)y2;

        if (y1 > y2) {
            GLfloat t = fy1; fy1 = fy2; fy2 = t;
        }

        j2d_glVertex2f(fx, fy1+0.2f);
        j2d_glVertex2f(fx, fy2+1.2f);
    } else {
        // diagonal
        GLfloat fx1 = (GLfloat)x1;
        GLfloat fy1 = (GLfloat)y1;
        GLfloat fx2 = (GLfloat)x2;
        GLfloat fy2 = (GLfloat)y2;

        if (x1 < x2) {
            fx1 += 0.2f;
            fx2 += 1.0f;
        } else {
            fx1 += 0.8f;
            fx2 -= 0.2f;
        }

        if (y1 < y2) {
            fy1 += 0.2f;
            fy2 += 1.0f;
        } else {
            fy1 += 0.8f;
            fy2 -= 0.2f;
        }

        j2d_glVertex2f(fx1, fy1);
        j2d_glVertex2f(fx2, fy2);
    }
}

void
OGLRenderer_DrawRect(OGLContext *oglc, jint x, jint y, jint w, jint h)
{
    J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_DrawRect");

    if (w < 0 || h < 0) {
        return;
    }

    RETURN_IF_NULL(oglc);

    if (w < 2 || h < 2) {
        // If one dimension is less than 2 then there is no
        // gap in the middle - draw a solid filled rectangle.
        CHECK_PREVIOUS_OP(GL_QUADS);
        GLRECT_BODY_XYWH(x, y, w+1, h+1);
    } else {
        GLfloat fx1 = ((GLfloat)x) + 0.2f;
        GLfloat fy1 = ((GLfloat)y) + 0.2f;
        GLfloat fx2 = fx1 + ((GLfloat)w);
        GLfloat fy2 = fy1 + ((GLfloat)h);

        // Avoid drawing the endpoints twice.
        // Also prefer including the endpoints in the
        // horizontal sections which draw pixels faster.

        CHECK_PREVIOUS_OP(GL_LINES);
        // top
        j2d_glVertex2f(fx1,      fy1);
        j2d_glVertex2f(fx2+1.0f, fy1);
        // right
        j2d_glVertex2f(fx2,      fy1+1.0f);
        j2d_glVertex2f(fx2,      fy2);
        // bottom
        j2d_glVertex2f(fx1,      fy2);
        j2d_glVertex2f(fx2+1.0f, fy2);
        // left
        j2d_glVertex2f(fx1,      fy1+1.0f);
        j2d_glVertex2f(fx1,      fy2);
    }
}

void
OGLRenderer_DrawPoly(OGLContext *oglc,
                     jint nPoints, jint isClosed,
                     jint transX, jint transY,
                     jint *xPoints, jint *yPoints)
{
    jboolean isEmpty = JNI_TRUE;
    jint mx, my;
    jint i;

    J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_DrawPoly");

    if (xPoints == NULL || yPoints == NULL) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
                      "OGLRenderer_DrawPoly: points array is null");
        return;
    }

    RETURN_IF_NULL(oglc);

    // Note that BufferedRenderPipe.drawPoly() has already rejected polys
    // with nPoints<2, so we can be certain here that we have nPoints>=2.

    mx = xPoints[0];
    my = yPoints[0];

    CHECK_PREVIOUS_OP(GL_LINE_STRIP);
    for (i = 0; i < nPoints; i++) {
        jint x = xPoints[i];
        jint y = yPoints[i];

        isEmpty = isEmpty && (x == mx && y == my);

        // Translate each vertex by a fraction so that we hit pixel centers.
        j2d_glVertex2f((GLfloat)(x + transX) + 0.5f,
                       (GLfloat)(y + transY) + 0.5f);
    }

    if (isClosed && !isEmpty &&
        (xPoints[nPoints-1] != mx ||
         yPoints[nPoints-1] != my))
    {
        // In this case, the polyline's start and end positions are
        // different and need to be closed manually; we do this by adding
        // one more segment back to the starting position.  Note that we
        // do not need to fill in the last pixel (as we do in the following
        // block) because we are returning to the starting pixel, which
        // has already been filled in.
        j2d_glVertex2f((GLfloat)(mx + transX) + 0.5f,
                       (GLfloat)(my + transY) + 0.5f);
        RESET_PREVIOUS_OP(); // so that we don't leave the line strip open
    } else if (!isClosed || isEmpty) {
        // OpenGL omits the last pixel in a polyline, so we fix this by
        // adding a one-pixel segment at the end.  Also, if the polyline
        // never went anywhere (isEmpty is true), we need to use this
        // workaround to ensure that a single pixel is touched.
        CHECK_PREVIOUS_OP(GL_LINES); // this closes the line strip first
        mx = xPoints[nPoints-1] + transX;
        my = yPoints[nPoints-1] + transY;
        j2d_glVertex2i(mx, my);
        j2d_glVertex2i(mx+1, my+1);
        // no need for RESET_PREVIOUS_OP, as the line strip is no longer open
    } else {
        RESET_PREVIOUS_OP(); // so that we don't leave the line strip open
    }
}

JNIEXPORT void JNICALL
Java_sun_java2d_opengl_OGLRenderer_drawPoly
    (JNIEnv *env, jobject oglr,
     jintArray xpointsArray, jintArray ypointsArray,
     jint nPoints, jboolean isClosed,
     jint transX, jint transY)
{
    jint *xPoints, *yPoints;

    J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_drawPoly");

    xPoints = (jint *)
        (*env)->GetPrimitiveArrayCritical(env, xpointsArray, NULL);
    if (xPoints != NULL) {
        yPoints = (jint *)
            (*env)->GetPrimitiveArrayCritical(env, ypointsArray, NULL);
        if (yPoints != NULL) {
            OGLContext *oglc = OGLRenderQueue_GetCurrentContext();

            OGLRenderer_DrawPoly(oglc,
                                 nPoints, isClosed,
                                 transX, transY,
                                 xPoints, yPoints);

            // 6358147: reset current state, and ensure rendering is
            // flushed to dest
            if (oglc != NULL) {
                RESET_PREVIOUS_OP();
                j2d_glFlush();
            }

            (*env)->ReleasePrimitiveArrayCritical(env, ypointsArray, yPoints,
                                                  JNI_ABORT);
        }
        (*env)->ReleasePrimitiveArrayCritical(env, xpointsArray, xPoints,
                                              JNI_ABORT);
    }
}

void
OGLRenderer_DrawScanlines(OGLContext *oglc,
                          jint scanlineCount, jint *scanlines)
{
    J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_DrawScanlines");

    RETURN_IF_NULL(oglc);
    RETURN_IF_NULL(scanlines);

    CHECK_PREVIOUS_OP(GL_LINES);
    while (scanlineCount > 0) {
        // Translate each vertex by a fraction so
        // that we hit pixel centers.
        GLfloat x1 = ((GLfloat)*(scanlines++)) + 0.2f;
        GLfloat x2 = ((GLfloat)*(scanlines++)) + 1.2f;
        GLfloat y  = ((GLfloat)*(scanlines++)) + 0.5f;
        j2d_glVertex2f(x1, y);
        j2d_glVertex2f(x2, y);
        scanlineCount--;
    }
}

void
OGLRenderer_FillRect(OGLContext *oglc, jint x, jint y, jint w, jint h)
{
    J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_FillRect");

    if (w <= 0 || h <= 0) {
        return;
    }

    RETURN_IF_NULL(oglc);

    CHECK_PREVIOUS_OP(GL_QUADS);
    GLRECT_BODY_XYWH(x, y, w, h);
}

void
OGLRenderer_FillSpans(OGLContext *oglc, jint spanCount, jint *spans)
{
    J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_FillSpans");

    RETURN_IF_NULL(oglc);
    RETURN_IF_NULL(spans);

    CHECK_PREVIOUS_OP(GL_QUADS);
    while (spanCount > 0) {
        jint x1 = *(spans++);
        jint y1 = *(spans++);
        jint x2 = *(spans++);
        jint y2 = *(spans++);
        GLRECT_BODY_XYXY(x1, y1, x2, y2);
        spanCount--;
    }
}

#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 */

Other Java examples (source code examples)

Here is a short list of links related to this Java OGLRenderer.c source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.