3172N/A/*
3261N/A * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
3172N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3172N/A *
3172N/A * This code is free software; you can redistribute it and/or modify it
3172N/A * under the terms of the GNU General Public License version 2 only, as
3172N/A * published by the Free Software Foundation. Oracle designates this
3172N/A * particular file as subject to the "Classpath" exception as provided
3172N/A * by Oracle in the LICENSE file that accompanied this code.
3172N/A *
3172N/A * This code is distributed in the hope that it will be useful, but WITHOUT
3172N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
3172N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
3172N/A * version 2 for more details (a copy is included in the LICENSE file that
3172N/A * accompanied this code).
3172N/A *
3172N/A * You should have received a copy of the GNU General Public License version
3172N/A * 2 along with this work; if not, write to the Free Software Foundation,
3172N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
3172N/A *
3172N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
3172N/A * or visit www.oracle.com if you need additional information or have any
3172N/A * questions.
3172N/A */
3172N/A
3172N/A#include "math.h"
3172N/A#include "GraphicsPrimitiveMgr.h"
3172N/A#include "LineUtils.h"
3172N/A#include "Trace.h"
3265N/A#include "ParallelogramUtils.h"
3172N/A
3172N/A#include "sun_java2d_loops_DrawParallelogram.h"
3172N/A
3172N/A#define HANDLE_PGRAM_EDGE(X1, Y1, X2, Y2, \
3172N/A pRasInfo, pixel, pPrim, pFunc, pCompInfo) \
3172N/A do { \
3172N/A jint ix1 = (jint) floor(X1); \
3172N/A jint ix2 = (jint) floor(X2); \
3172N/A jint iy1 = (jint) floor(Y1); \
3172N/A jint iy2 = (jint) floor(Y2); \
3172N/A LineUtils_ProcessLine(pRasInfo, pixel, \
3172N/A pFunc, pPrim, pCompInfo, \
3172N/A ix1, iy1, ix2, iy2, JNI_TRUE); \
3172N/A } while (0)
3172N/A
3172N/Atypedef struct {
3172N/A jdouble x0;
3172N/A jdouble y0;
3172N/A jdouble y1;
3172N/A jdouble slope;
3172N/A jlong dx;
3172N/A jint ystart;
3172N/A jint yend;
3172N/A} EdgeInfo;
3172N/A
3172N/A#define STORE_EDGE(pEDGE, X0, Y0, Y1, SLOPE, DELTAX) \
3172N/A do { \
3172N/A (pEDGE)->x0 = (X0); \
3172N/A (pEDGE)->y0 = (Y0); \
3172N/A (pEDGE)->y1 = (Y1); \
3172N/A (pEDGE)->slope = (SLOPE); \
3172N/A (pEDGE)->dx = (DELTAX); \
3172N/A (pEDGE)->ystart = (jint) floor((Y0) + 0.5); \
3172N/A (pEDGE)->yend = (jint) floor((Y1) + 0.5); \
3172N/A } while (0)
3172N/A
3172N/A#define STORE_PGRAM(pLTEDGE, pRTEDGE, \
3172N/A X0, Y0, dX1, dY1, dX2, dY2, \
3172N/A SLOPE1, SLOPE2, DELTAX1, DELTAX2) \
3172N/A do { \
3172N/A STORE_EDGE((pLTEDGE)+0, \
3172N/A (X0), (Y0), (Y0) + (dY1), \
3172N/A (SLOPE1), (DELTAX1)); \
3172N/A STORE_EDGE((pRTEDGE)+0, \
3172N/A (X0), (Y0), (Y0) + (dY2), \
3172N/A (SLOPE2), (DELTAX2)); \
3172N/A STORE_EDGE((pLTEDGE)+1, \
3172N/A (X0) + (dX1), (Y0) + (dY1), (Y0) + (dY1) + (dY2), \
3172N/A (SLOPE2), (DELTAX2)); \
3172N/A STORE_EDGE((pRTEDGE)+1, \
3172N/A (X0) + (dX2), (Y0) + (dY2), (Y0) + (dY1) + (dY2), \
3172N/A (SLOPE1), (DELTAX1)); \
3172N/A } while (0)
3172N/A
3172N/A/*
3172N/A * Class: sun_java2d_loops_DrawParallelogram
3172N/A * Method: DrawParallelogram
3172N/A * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;DDDDDDDD)V
3172N/A */
3172N/AJNIEXPORT void JNICALL
3172N/AJava_sun_java2d_loops_DrawParallelogram_DrawParallelogram
3172N/A (JNIEnv *env, jobject self,
3172N/A jobject sg2d, jobject sData,
3172N/A jdouble x0, jdouble y0,
3172N/A jdouble dx1, jdouble dy1,
3172N/A jdouble dx2, jdouble dy2,
3172N/A jdouble lw1, jdouble lw2)
3172N/A{
3172N/A SurfaceDataOps *sdOps;
3172N/A SurfaceDataRasInfo rasInfo;
3172N/A NativePrimitive *pPrim;
3172N/A CompositeInfo compInfo;
3172N/A jint pixel;
3172N/A EdgeInfo edges[8];
3172N/A EdgeInfo *active[4];
3172N/A jint ix1, iy1, ix2, iy2;
3172N/A jdouble ldx1, ldy1, ldx2, ldy2;
3172N/A jdouble ox0, oy0;
3172N/A
3172N/A /*
3172N/A * Sort parallelogram by y values, ensure that each delta vector
3172N/A * has a non-negative y delta.
3172N/A */
3265N/A SORT_PGRAM(x0, y0, dx1, dy1, dx2, dy2,
3265N/A v = lw1; lw1 = lw2; lw2 = v;);
3172N/A
3172N/A // dx,dy for line width in the "1" and "2" directions.
3172N/A ldx1 = dx1 * lw1;
3172N/A ldy1 = dy1 * lw1;
3172N/A ldx2 = dx2 * lw2;
3172N/A ldy2 = dy2 * lw2;
3172N/A
3172N/A // calculate origin of the outer parallelogram
3172N/A ox0 = x0 - (ldx1 + ldx2) / 2.0;
3172N/A oy0 = y0 - (ldy1 + ldy2) / 2.0;
3172N/A
3265N/A PGRAM_MIN_MAX(ix1, ix2, ox0, dx1+ldx1, dx2+ldx2, JNI_FALSE);
3172N/A iy1 = (jint) floor(oy0 + 0.5);
3172N/A iy2 = (jint) floor(oy0 + dy1 + ldy1 + dy2 + ldy2 + 0.5);
3172N/A
3172N/A pPrim = GetNativePrim(env, self);
3172N/A if (pPrim == NULL) {
3172N/A return;
3172N/A }
3172N/A pixel = GrPrim_Sg2dGetPixel(env, sg2d);
3172N/A if (pPrim->pCompType->getCompInfo != NULL) {
3172N/A GrPrim_Sg2dGetCompInfo(env, sg2d, pPrim, &compInfo);
3172N/A }
3172N/A
3172N/A sdOps = SurfaceData_GetOps(env, sData);
3172N/A if (sdOps == NULL) {
3172N/A return;
3172N/A }
3172N/A
3172N/A GrPrim_Sg2dGetClip(env, sg2d, &rasInfo.bounds);
3172N/A SurfaceData_IntersectBoundsXYXY(&rasInfo.bounds, ix1, iy1, ix2, iy2);
3172N/A if (rasInfo.bounds.y2 <= rasInfo.bounds.y1 ||
3172N/A rasInfo.bounds.x2 <= rasInfo.bounds.x1)
3172N/A {
3172N/A return;
3172N/A }
3172N/A
3172N/A if (sdOps->Lock(env, sdOps, &rasInfo, pPrim->dstflags) != SD_SUCCESS) {
3172N/A return;
3172N/A }
3172N/A
3172N/A ix1 = rasInfo.bounds.x1;
3172N/A iy1 = rasInfo.bounds.y1;
3172N/A ix2 = rasInfo.bounds.x2;
3172N/A iy2 = rasInfo.bounds.y2;
3172N/A if (ix2 > ix1 && iy2 > iy1) {
3172N/A sdOps->GetRasInfo(env, sdOps, &rasInfo);
3172N/A if (rasInfo.rasBase) {
3172N/A jdouble lslope, rslope;
3172N/A jlong ldx, rdx;
3172N/A jint loy, hiy, numedges;
3172N/A FillParallelogramFunc *pFill =
3172N/A pPrim->funcs.drawparallelogram->fillpgram;
3172N/A
3172N/A lslope = (dy1 == 0) ? 0 : dx1 / dy1;
3172N/A rslope = (dy2 == 0) ? 0 : dx2 / dy2;
3172N/A ldx = DblToLong(lslope);
3172N/A rdx = DblToLong(rslope);
3172N/A
3172N/A // Only need to generate 4 quads if the interior still
3172N/A // has a hole in it (i.e. if the line width ratios were
3172N/A // both less than 1.0)
3265N/A if (lw1 < 1.0 && lw2 < 1.0) {
3172N/A // If the line widths are both less than a pixel wide
3172N/A // then we can use a drawline function instead for even
3172N/A // more performance.
3172N/A lw1 = sqrt(ldx1*ldx1 + ldy1*ldy1);
3172N/A lw2 = sqrt(ldx2*ldx2 + ldy2*ldy2);
3172N/A if (lw1 <= 1.0001 && lw2 <= 1.0001) {
3172N/A jdouble x3, y3;
3172N/A DrawLineFunc *pLine =
3172N/A pPrim->funcs.drawparallelogram->drawline;
3172N/A
3172N/A x3 = (dx1 += x0);
3172N/A y3 = (dy1 += y0);
3172N/A x3 += dx2;
3172N/A y3 += dy2;
3172N/A dx2 += x0;
3172N/A dy2 += y0;
3172N/A
3172N/A HANDLE_PGRAM_EDGE( x0, y0, dx1, dy1,
3172N/A &rasInfo, pixel, pPrim, pLine, &compInfo);
3172N/A HANDLE_PGRAM_EDGE(dx1, dy1, x3, y3,
3172N/A &rasInfo, pixel, pPrim, pLine, &compInfo);
3172N/A HANDLE_PGRAM_EDGE( x3, y3, dx2, dy2,
3172N/A &rasInfo, pixel, pPrim, pLine, &compInfo);
3172N/A HANDLE_PGRAM_EDGE(dx2, dy2, x0, y0,
3172N/A &rasInfo, pixel, pPrim, pLine, &compInfo);
3172N/A SurfaceData_InvokeRelease(env, sdOps, &rasInfo);
3172N/A SurfaceData_InvokeUnlock(env, sdOps, &rasInfo);
3172N/A return;
3172N/A }
3172N/A
3172N/A // To simplify the edge management below we presort the
3172N/A // inner and outer edges so that they are globally sorted
3172N/A // from left to right. If you scan across the array of
3172N/A // edges for a given Y range then the edges you encounter
3172N/A // will be sorted in X as well.
3172N/A // If AB are left top and bottom edges of outer parallelogram,
3172N/A // and CD are the right pair of edges, and abcd are the
3172N/A // corresponding inner parallelogram edges then we want them
3172N/A // sorted as ABabcdCD to ensure this horizontal ordering.
3172N/A // Conceptually it is like 2 pairs of nested parentheses.
3172N/A STORE_PGRAM(edges + 2, edges + 4,
3172N/A ox0 + ldx1 + ldx2, oy0 + ldy1 + ldy2,
3172N/A dx1 - ldx1, dy1 - ldy1,
3172N/A dx2 - ldx2, dy2 - ldy2,
3172N/A lslope, rslope, ldx, rdx);
3172N/A numedges = 8;
3172N/A } else {
3172N/A // The line width ratios were large enough to consume
3172N/A // the entire hole in the middle of the parallelogram
3172N/A // so we can just issue one large quad for the outer
3172N/A // parallelogram.
3172N/A numedges = 4;
3172N/A }
3172N/A
3172N/A // The outer parallelogram always goes in the first two
3172N/A // and last two entries in the array so we either have
3172N/A // ABabcdCD ordering for 8 edges or ABCD ordering for 4
3172N/A // edges. See comment above where we store the inner
3172N/A // parallelogram for a more complete description.
3172N/A STORE_PGRAM(edges + 0, edges + numedges-2,
3172N/A ox0, oy0,
3172N/A dx1 + ldx1, dy1 + ldy1,
3172N/A dx2 + ldx2, dy2 + ldy2,
3172N/A lslope, rslope, ldx, rdx);
3172N/A
3172N/A loy = edges[0].ystart;
3172N/A if (loy < iy1) loy = iy1;
3172N/A while (loy < iy2) {
3172N/A jint numactive = 0;
3172N/A jint cur;
3172N/A
3172N/A hiy = iy2;
3172N/A // Maintaining a sorted edge list is probably overkill for
3172N/A // 4 or 8 edges. The indices chosen above for storing the
3172N/A // inner and outer left and right edges already guarantee
3172N/A // left to right ordering so we just need to scan for edges
3172N/A // that overlap the current Y range (and also determine the
3172N/A // maximum Y value for which the range is valid).
3172N/A for (cur = 0; cur < numedges; cur++) {
3172N/A EdgeInfo *pEdge = &edges[cur];
3172N/A jint yend = pEdge->yend;
3172N/A if (loy < yend) {
3172N/A // This edge is still in play, have we reached it yet?
3172N/A jint ystart = pEdge->ystart;
3172N/A if (loy < ystart) {
3172N/A // This edge is not active (yet)
3172N/A // Stop before we get to the top of it
3172N/A if (hiy > ystart) hiy = ystart;
3172N/A } else {
3172N/A // This edge is active, store it
3172N/A active[numactive++] = pEdge;
3172N/A // And stop when we get to the bottom of it
3172N/A if (hiy > yend) hiy = yend;
3172N/A }
3172N/A }
3172N/A }
3172N/A#ifdef DEBUG
3172N/A if ((numactive & 1) != 0) {
3172N/A J2dTraceLn1(J2D_TRACE_ERROR,
3172N/A "DrawParallelogram: "
3172N/A "ODD NUMBER OF PGRAM EDGES (%d)!!",
3172N/A numactive);
3172N/A }
3172N/A#endif
3172N/A for (cur = 0; cur < numactive; cur += 2) {
3172N/A EdgeInfo *pLeft = active[cur+0];
3172N/A EdgeInfo *pRight = active[cur+1];
3172N/A jlong lx = PGRAM_INIT_X(loy,
3172N/A pLeft->x0, pLeft->y0,
3172N/A pLeft->slope);
3172N/A jlong rx = PGRAM_INIT_X(loy,
3172N/A pRight->x0, pRight->y0,
3172N/A pRight->slope);
3172N/A (*pFill)(&rasInfo,
3172N/A ix1, loy, ix2, hiy,
3172N/A lx, pLeft->dx,
3172N/A rx, pRight->dx,
3172N/A pixel, pPrim, &compInfo);
3172N/A }
3172N/A loy = hiy;
3172N/A }
3172N/A }
3172N/A SurfaceData_InvokeRelease(env, sdOps, &rasInfo);
3172N/A }
3172N/A SurfaceData_InvokeUnlock(env, sdOps, &rasInfo);
3172N/A}