Path: blob/master/src/java.desktop/share/native/common/java2d/opengl/OGLRenderer.c
41159 views
/*1* Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#ifndef HEADLESS2627#include <jlong.h>28#include <jni_util.h>29#include <math.h>3031#include "sun_java2d_opengl_OGLRenderer.h"3233#include "OGLRenderer.h"34#include "OGLRenderQueue.h"35#include "OGLSurfaceData.h"3637/**38* Note: Some of the methods in this file apply a "magic number"39* translation to line segments. The OpenGL specification lays out the40* "diamond exit rule" for line rasterization, but it is loose enough to41* allow for a wide range of line rendering hardware. (It appears that42* some hardware, such as the Nvidia GeForce2 series, does not even meet43* the spec in all cases.) As such it is difficult to find a mapping44* between the Java2D and OpenGL line specs that works consistently across45* all hardware combinations.46*47* Therefore the "magic numbers" you see here have been empirically derived48* after testing on a variety of graphics hardware in order to find some49* reasonable middle ground between the two specifications. The general50* approach is to apply a fractional translation to vertices so that they51* hit pixel centers and therefore touch the same pixels as in our other52* pipelines. Emphasis was placed on finding values so that OGL lines with53* a slope of +/- 1 hit all the same pixels as our other (software) loops.54* The stepping in other diagonal lines rendered with OGL may deviate55* slightly from those rendered with our software loops, but the most56* important thing is that these magic numbers ensure that all OGL lines57* hit the same endpoints as our software loops.58*59* If you find it necessary to change any of these magic numbers in the60* future, just be sure that you test the changes across a variety of61* hardware to ensure consistent rendering everywhere.62*/6364void65OGLRenderer_DrawLine(OGLContext *oglc, jint x1, jint y1, jint x2, jint y2)66{67J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_DrawLine");6869RETURN_IF_NULL(oglc);7071CHECK_PREVIOUS_OP(GL_LINES);7273if (y1 == y2) {74// horizontal75GLfloat fx1 = (GLfloat)x1;76GLfloat fx2 = (GLfloat)x2;77GLfloat fy = ((GLfloat)y1) + 0.2f;7879if (x1 > x2) {80GLfloat t = fx1; fx1 = fx2; fx2 = t;81}8283j2d_glVertex2f(fx1+0.2f, fy);84j2d_glVertex2f(fx2+1.2f, fy);85} else if (x1 == x2) {86// vertical87GLfloat fx = ((GLfloat)x1) + 0.2f;88GLfloat fy1 = (GLfloat)y1;89GLfloat fy2 = (GLfloat)y2;9091if (y1 > y2) {92GLfloat t = fy1; fy1 = fy2; fy2 = t;93}9495j2d_glVertex2f(fx, fy1+0.2f);96j2d_glVertex2f(fx, fy2+1.2f);97} else {98// diagonal99GLfloat fx1 = (GLfloat)x1;100GLfloat fy1 = (GLfloat)y1;101GLfloat fx2 = (GLfloat)x2;102GLfloat fy2 = (GLfloat)y2;103104if (x1 < x2) {105fx1 += 0.2f;106fx2 += 1.0f;107} else {108fx1 += 0.8f;109fx2 -= 0.2f;110}111112if (y1 < y2) {113fy1 += 0.2f;114fy2 += 1.0f;115} else {116fy1 += 0.8f;117fy2 -= 0.2f;118}119120j2d_glVertex2f(fx1, fy1);121j2d_glVertex2f(fx2, fy2);122}123}124125void126OGLRenderer_DrawRect(OGLContext *oglc, jint x, jint y, jint w, jint h)127{128J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_DrawRect");129130if (w < 0 || h < 0) {131return;132}133134RETURN_IF_NULL(oglc);135136if (w < 2 || h < 2) {137// If one dimension is less than 2 then there is no138// gap in the middle - draw a solid filled rectangle.139CHECK_PREVIOUS_OP(GL_QUADS);140GLRECT_BODY_XYWH(x, y, w+1, h+1);141} else {142GLfloat fx1 = ((GLfloat)x) + 0.2f;143GLfloat fy1 = ((GLfloat)y) + 0.2f;144GLfloat fx2 = fx1 + ((GLfloat)w);145GLfloat fy2 = fy1 + ((GLfloat)h);146147// Avoid drawing the endpoints twice.148// Also prefer including the endpoints in the149// horizontal sections which draw pixels faster.150151CHECK_PREVIOUS_OP(GL_LINES);152// top153j2d_glVertex2f(fx1, fy1);154j2d_glVertex2f(fx2+1.0f, fy1);155// right156j2d_glVertex2f(fx2, fy1+1.0f);157j2d_glVertex2f(fx2, fy2);158// bottom159j2d_glVertex2f(fx1, fy2);160j2d_glVertex2f(fx2+1.0f, fy2);161// left162j2d_glVertex2f(fx1, fy1+1.0f);163j2d_glVertex2f(fx1, fy2);164}165}166167void168OGLRenderer_DrawPoly(OGLContext *oglc,169jint nPoints, jint isClosed,170jint transX, jint transY,171jint *xPoints, jint *yPoints)172{173jboolean isEmpty = JNI_TRUE;174jint mx, my;175jint i;176177J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_DrawPoly");178179if (xPoints == NULL || yPoints == NULL) {180J2dRlsTraceLn(J2D_TRACE_ERROR,181"OGLRenderer_DrawPoly: points array is null");182return;183}184185RETURN_IF_NULL(oglc);186187// Note that BufferedRenderPipe.drawPoly() has already rejected polys188// with nPoints<2, so we can be certain here that we have nPoints>=2.189190mx = xPoints[0];191my = yPoints[0];192193CHECK_PREVIOUS_OP(GL_LINE_STRIP);194for (i = 0; i < nPoints; i++) {195jint x = xPoints[i];196jint y = yPoints[i];197198isEmpty = isEmpty && (x == mx && y == my);199200// Translate each vertex by a fraction so that we hit pixel centers.201j2d_glVertex2f((GLfloat)(x + transX) + 0.5f,202(GLfloat)(y + transY) + 0.5f);203}204205if (isClosed && !isEmpty &&206(xPoints[nPoints-1] != mx ||207yPoints[nPoints-1] != my))208{209// In this case, the polyline's start and end positions are210// different and need to be closed manually; we do this by adding211// one more segment back to the starting position. Note that we212// do not need to fill in the last pixel (as we do in the following213// block) because we are returning to the starting pixel, which214// has already been filled in.215j2d_glVertex2f((GLfloat)(mx + transX) + 0.5f,216(GLfloat)(my + transY) + 0.5f);217RESET_PREVIOUS_OP(); // so that we don't leave the line strip open218} else if (!isClosed || isEmpty) {219// OpenGL omits the last pixel in a polyline, so we fix this by220// adding a one-pixel segment at the end. Also, if the polyline221// never went anywhere (isEmpty is true), we need to use this222// workaround to ensure that a single pixel is touched.223CHECK_PREVIOUS_OP(GL_LINES); // this closes the line strip first224mx = xPoints[nPoints-1] + transX;225my = yPoints[nPoints-1] + transY;226j2d_glVertex2i(mx, my);227j2d_glVertex2i(mx+1, my+1);228// no need for RESET_PREVIOUS_OP, as the line strip is no longer open229} else {230RESET_PREVIOUS_OP(); // so that we don't leave the line strip open231}232}233234JNIEXPORT void JNICALL235Java_sun_java2d_opengl_OGLRenderer_drawPoly236(JNIEnv *env, jobject oglr,237jintArray xpointsArray, jintArray ypointsArray,238jint nPoints, jboolean isClosed,239jint transX, jint transY)240{241jint *xPoints, *yPoints;242243J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_drawPoly");244245xPoints = (jint *)246(*env)->GetPrimitiveArrayCritical(env, xpointsArray, NULL);247if (xPoints != NULL) {248yPoints = (jint *)249(*env)->GetPrimitiveArrayCritical(env, ypointsArray, NULL);250if (yPoints != NULL) {251OGLContext *oglc = OGLRenderQueue_GetCurrentContext();252253OGLRenderer_DrawPoly(oglc,254nPoints, isClosed,255transX, transY,256xPoints, yPoints);257258// 6358147: reset current state, and ensure rendering is259// flushed to dest260if (oglc != NULL) {261RESET_PREVIOUS_OP();262j2d_glFlush();263}264265(*env)->ReleasePrimitiveArrayCritical(env, ypointsArray, yPoints,266JNI_ABORT);267}268(*env)->ReleasePrimitiveArrayCritical(env, xpointsArray, xPoints,269JNI_ABORT);270}271}272273void274OGLRenderer_DrawScanlines(OGLContext *oglc,275jint scanlineCount, jint *scanlines)276{277J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_DrawScanlines");278279RETURN_IF_NULL(oglc);280RETURN_IF_NULL(scanlines);281282CHECK_PREVIOUS_OP(GL_LINES);283while (scanlineCount > 0) {284// Translate each vertex by a fraction so285// that we hit pixel centers.286GLfloat x1 = ((GLfloat)*(scanlines++)) + 0.2f;287GLfloat x2 = ((GLfloat)*(scanlines++)) + 1.2f;288GLfloat y = ((GLfloat)*(scanlines++)) + 0.5f;289j2d_glVertex2f(x1, y);290j2d_glVertex2f(x2, y);291scanlineCount--;292}293}294295void296OGLRenderer_FillRect(OGLContext *oglc, jint x, jint y, jint w, jint h)297{298J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_FillRect");299300if (w <= 0 || h <= 0) {301return;302}303304RETURN_IF_NULL(oglc);305306CHECK_PREVIOUS_OP(GL_QUADS);307GLRECT_BODY_XYWH(x, y, w, h);308}309310void311OGLRenderer_FillSpans(OGLContext *oglc, jint spanCount, jint *spans)312{313J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_FillSpans");314315RETURN_IF_NULL(oglc);316RETURN_IF_NULL(spans);317318CHECK_PREVIOUS_OP(GL_QUADS);319while (spanCount > 0) {320jint x1 = *(spans++);321jint y1 = *(spans++);322jint x2 = *(spans++);323jint y2 = *(spans++);324GLRECT_BODY_XYXY(x1, y1, x2, y2);325spanCount--;326}327}328329#define FILL_PGRAM(fx11, fy11, dx21, dy21, dx12, dy12) \330do { \331j2d_glVertex2f(fx11, fy11); \332j2d_glVertex2f(fx11 + dx21, fy11 + dy21); \333j2d_glVertex2f(fx11 + dx21 + dx12, fy11 + dy21 + dy12); \334j2d_glVertex2f(fx11 + dx12, fy11 + dy12); \335} while (0)336337void338OGLRenderer_FillParallelogram(OGLContext *oglc,339jfloat fx11, jfloat fy11,340jfloat dx21, jfloat dy21,341jfloat dx12, jfloat dy12)342{343J2dTraceLn6(J2D_TRACE_INFO,344"OGLRenderer_FillParallelogram "345"(x=%6.2f y=%6.2f "346"dx1=%6.2f dy1=%6.2f "347"dx2=%6.2f dy2=%6.2f)",348fx11, fy11,349dx21, dy21,350dx12, dy12);351352RETURN_IF_NULL(oglc);353354CHECK_PREVIOUS_OP(GL_QUADS);355356FILL_PGRAM(fx11, fy11, dx21, dy21, dx12, dy12);357}358359void360OGLRenderer_DrawParallelogram(OGLContext *oglc,361jfloat fx11, jfloat fy11,362jfloat dx21, jfloat dy21,363jfloat dx12, jfloat dy12,364jfloat lwr21, jfloat lwr12)365{366// dx,dy for line width in the "21" and "12" directions.367jfloat ldx21 = dx21 * lwr21;368jfloat ldy21 = dy21 * lwr21;369jfloat ldx12 = dx12 * lwr12;370jfloat ldy12 = dy12 * lwr12;371372// calculate origin of the outer parallelogram373jfloat ox11 = fx11 - (ldx21 + ldx12) / 2.0f;374jfloat oy11 = fy11 - (ldy21 + ldy12) / 2.0f;375376J2dTraceLn8(J2D_TRACE_INFO,377"OGLRenderer_DrawParallelogram "378"(x=%6.2f y=%6.2f "379"dx1=%6.2f dy1=%6.2f lwr1=%6.2f "380"dx2=%6.2f dy2=%6.2f lwr2=%6.2f)",381fx11, fy11,382dx21, dy21, lwr21,383dx12, dy12, lwr12);384385RETURN_IF_NULL(oglc);386387CHECK_PREVIOUS_OP(GL_QUADS);388389// Only need to generate 4 quads if the interior still390// has a hole in it (i.e. if the line width ratio was391// less than 1.0)392if (lwr21 < 1.0f && lwr12 < 1.0f) {393// Note: "TOP", "BOTTOM", "LEFT" and "RIGHT" here are394// relative to whether the dxNN variables are positive395// and negative. The math works fine regardless of396// their signs, but for conceptual simplicity the397// comments will refer to the sides as if the dxNN398// were all positive. "TOP" and "BOTTOM" segments399// are defined by the dxy21 deltas. "LEFT" and "RIGHT"400// segments are defined by the dxy12 deltas.401402// Each segment includes its starting corner and comes403// to just short of the following corner. Thus, each404// corner is included just once and the only lengths405// needed are the original parallelogram delta lengths406// and the "line width deltas". The sides will cover407// the following relative territories:408//409// T T T T T R410// L R411// L R412// L R413// L R414// L B B B B B415416// TOP segment, to left side of RIGHT edge417// "width" of original pgram, "height" of hor. line size418fx11 = ox11;419fy11 = oy11;420FILL_PGRAM(fx11, fy11, dx21, dy21, ldx12, ldy12);421422// RIGHT segment, to top of BOTTOM edge423// "width" of vert. line size , "height" of original pgram424fx11 = ox11 + dx21;425fy11 = oy11 + dy21;426FILL_PGRAM(fx11, fy11, ldx21, ldy21, dx12, dy12);427428// BOTTOM segment, from right side of LEFT edge429// "width" of original pgram, "height" of hor. line size430fx11 = ox11 + dx12 + ldx21;431fy11 = oy11 + dy12 + ldy21;432FILL_PGRAM(fx11, fy11, dx21, dy21, ldx12, ldy12);433434// LEFT segment, from bottom of TOP edge435// "width" of vert. line size , "height" of inner pgram436fx11 = ox11 + ldx12;437fy11 = oy11 + ldy12;438FILL_PGRAM(fx11, fy11, ldx21, ldy21, dx12, dy12);439} else {440// The line width ratios were large enough to consume441// the entire hole in the middle of the parallelogram442// so we can just issue one large quad for the outer443// parallelogram.444dx21 += ldx21;445dy21 += ldy21;446dx12 += ldx12;447dy12 += ldy12;448FILL_PGRAM(ox11, oy11, dx21, dy21, dx12, dy12);449}450}451452static GLhandleARB aaPgramProgram = 0;453454/*455* This shader fills the space between an outer and inner parallelogram.456* It can be used to draw an outline by specifying both inner and outer457* values. It fills pixels by estimating what portion falls inside the458* outer shape, and subtracting an estimate of what portion falls inside459* the inner shape. Specifying both inner and outer values produces a460* standard "wide outline". Specifying an inner shape that falls far461* outside the outer shape allows the same shader to fill the outer462* shape entirely since pixels that fall within the outer shape are never463* inside the inner shape and so they are filled based solely on their464* coverage of the outer shape.465*466* The setup code renders this shader over the bounds of the outer467* shape (or the only shape in the case of a fill operation) and468* sets the texture 0 coordinates so that 0,0=>0,1=>1,1=>1,0 in those469* texture coordinates map to the four corners of the parallelogram.470* Similarly the texture 1 coordinates map the inner shape to the471* unit square as well, but in a different coordinate system.472*473* When viewed in the texture coordinate systems the parallelograms474* we are filling are unit squares, but the pixels have then become475* tiny parallelograms themselves. Both of the texture coordinate476* systems are affine transforms so the rate of change in X and Y477* of the texture coordinates are essentially constants and happen478* to correspond to the size and direction of the slanted sides of479* the distorted pixels relative to the "square mapped" boundary480* of the parallelograms.481*482* The shader uses the dFdx() and dFdy() functions to measure the "rate483* of change" of these texture coordinates and thus gets an accurate484* measure of the size and shape of a pixel relative to the two485* parallelograms. It then uses the bounds of the size and shape486* of a pixel to intersect with the unit square to estimate the487* coverage of the pixel. Unfortunately, without a lot more work488* to calculate the exact area of intersection between a unit489* square (the original parallelogram) and a parallelogram (the490* distorted pixel), this shader only approximates the pixel491* coverage, but emperically the estimate is very useful and492* produces visually pleasing results, if not theoretically accurate.493*/494static const char *aaPgramShaderSource =495"void main() {"496// Calculate the vectors for the "legs" of the pixel parallelogram497// for the outer parallelogram.498" vec2 oleg1 = dFdx(gl_TexCoord[0].st);"499" vec2 oleg2 = dFdy(gl_TexCoord[0].st);"500// Calculate the bounds of the distorted pixel parallelogram.501" vec2 corner = gl_TexCoord[0].st - (oleg1+oleg2)/2.0;"502" vec2 omin = min(corner, corner+oleg1);"503" omin = min(omin, corner+oleg2);"504" omin = min(omin, corner+oleg1+oleg2);"505" vec2 omax = max(corner, corner+oleg1);"506" omax = max(omax, corner+oleg2);"507" omax = max(omax, corner+oleg1+oleg2);"508// Calculate the vectors for the "legs" of the pixel parallelogram509// for the inner parallelogram.510" vec2 ileg1 = dFdx(gl_TexCoord[1].st);"511" vec2 ileg2 = dFdy(gl_TexCoord[1].st);"512// Calculate the bounds of the distorted pixel parallelogram.513" corner = gl_TexCoord[1].st - (ileg1+ileg2)/2.0;"514" vec2 imin = min(corner, corner+ileg1);"515" imin = min(imin, corner+ileg2);"516" imin = min(imin, corner+ileg1+ileg2);"517" vec2 imax = max(corner, corner+ileg1);"518" imax = max(imax, corner+ileg2);"519" imax = max(imax, corner+ileg1+ileg2);"520// Clamp the bounds of the parallelograms to the unit square to521// estimate the intersection of the pixel parallelogram with522// the unit square. The ratio of the 2 rectangle areas is a523// reasonable estimate of the proportion of coverage.524" vec2 o1 = clamp(omin, 0.0, 1.0);"525" vec2 o2 = clamp(omax, 0.0, 1.0);"526" float oint = (o2.y-o1.y)*(o2.x-o1.x);"527" float oarea = (omax.y-omin.y)*(omax.x-omin.x);"528" vec2 i1 = clamp(imin, 0.0, 1.0);"529" vec2 i2 = clamp(imax, 0.0, 1.0);"530" float iint = (i2.y-i1.y)*(i2.x-i1.x);"531" float iarea = (imax.y-imin.y)*(imax.x-imin.x);"532// Proportion of pixel in outer shape minus the proportion533// of pixel in the inner shape == the coverage of the pixel534// in the area between the two.535" float coverage = oint/oarea - iint / iarea;"536" gl_FragColor = gl_Color * coverage;"537"}";538539#define ADJUST_PGRAM(V1, DV, V2) \540do { \541if ((DV) >= 0) { \542(V2) += (DV); \543} else { \544(V1) += (DV); \545} \546} while (0)547548// Invert the following transform:549// DeltaT(0, 0) == (0, 0)550// DeltaT(1, 0) == (DX1, DY1)551// DeltaT(0, 1) == (DX2, DY2)552// DeltaT(1, 1) == (DX1+DX2, DY1+DY2)553// TM00 = DX1, TM01 = DX2, (TM02 = X11)554// TM10 = DY1, TM11 = DY2, (TM12 = Y11)555// Determinant = TM00*TM11 - TM01*TM10556// = DX1*DY2 - DX2*DY1557// Inverse is:558// IM00 = TM11/det, IM01 = -TM01/det559// IM10 = -TM10/det, IM11 = TM00/det560// IM02 = (TM01 * TM12 - TM11 * TM02) / det,561// IM12 = (TM10 * TM02 - TM00 * TM12) / det,562563#define DECLARE_MATRIX(MAT) \564jfloat MAT ## 00, MAT ## 01, MAT ## 02, MAT ## 10, MAT ## 11, MAT ## 12565566#define GET_INVERTED_MATRIX(MAT, X11, Y11, DX1, DY1, DX2, DY2, RET_CODE) \567do { \568jfloat det = DX1*DY2 - DX2*DY1; \569if (det == 0) { \570RET_CODE; \571} \572MAT ## 00 = DY2/det; \573MAT ## 01 = -DX2/det; \574MAT ## 10 = -DY1/det; \575MAT ## 11 = DX1/det; \576MAT ## 02 = (DX2 * Y11 - DY2 * X11) / det; \577MAT ## 12 = (DY1 * X11 - DX1 * Y11) / det; \578} while (0)579580#define TRANSFORM(MAT, TX, TY, X, Y) \581do { \582TX = (X) * MAT ## 00 + (Y) * MAT ## 01 + MAT ## 02; \583TY = (X) * MAT ## 10 + (Y) * MAT ## 11 + MAT ## 12; \584} while (0)585586void587OGLRenderer_FillAAParallelogram(OGLContext *oglc, OGLSDOps *dstOps,588jfloat fx11, jfloat fy11,589jfloat dx21, jfloat dy21,590jfloat dx12, jfloat dy12)591{592DECLARE_MATRIX(om);593// parameters for parallelogram bounding box594jfloat bx11, by11, bx22, by22;595// parameters for uv texture coordinates of parallelogram corners596jfloat u11, v11, u12, v12, u21, v21, u22, v22;597598J2dTraceLn6(J2D_TRACE_INFO,599"OGLRenderer_FillAAParallelogram "600"(x=%6.2f y=%6.2f "601"dx1=%6.2f dy1=%6.2f "602"dx2=%6.2f dy2=%6.2f)",603fx11, fy11,604dx21, dy21,605dx12, dy12);606607RETURN_IF_NULL(oglc);608RETURN_IF_NULL(dstOps);609610GET_INVERTED_MATRIX(om, fx11, fy11, dx21, dy21, dx12, dy12,611return);612613CHECK_PREVIOUS_OP(OGL_STATE_PGRAM_OP);614615bx11 = bx22 = fx11;616by11 = by22 = fy11;617ADJUST_PGRAM(bx11, dx21, bx22);618ADJUST_PGRAM(by11, dy21, by22);619ADJUST_PGRAM(bx11, dx12, bx22);620ADJUST_PGRAM(by11, dy12, by22);621bx11 = (jfloat) floor(bx11);622by11 = (jfloat) floor(by11);623bx22 = (jfloat) ceil(bx22);624by22 = (jfloat) ceil(by22);625626TRANSFORM(om, u11, v11, bx11, by11);627TRANSFORM(om, u21, v21, bx22, by11);628TRANSFORM(om, u12, v12, bx11, by22);629TRANSFORM(om, u22, v22, bx22, by22);630631j2d_glBegin(GL_QUADS);632j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u11, v11);633j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 5.f, 5.f);634j2d_glVertex2f(bx11, by11);635j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u21, v21);636j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 6.f, 5.f);637j2d_glVertex2f(bx22, by11);638j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u22, v22);639j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 6.f, 6.f);640j2d_glVertex2f(bx22, by22);641j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u12, v12);642j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 5.f, 6.f);643j2d_glVertex2f(bx11, by22);644j2d_glEnd();645}646647void648OGLRenderer_FillAAParallelogramInnerOuter(OGLContext *oglc, OGLSDOps *dstOps,649jfloat ox11, jfloat oy11,650jfloat ox21, jfloat oy21,651jfloat ox12, jfloat oy12,652jfloat ix11, jfloat iy11,653jfloat ix21, jfloat iy21,654jfloat ix12, jfloat iy12)655{656DECLARE_MATRIX(om);657DECLARE_MATRIX(im);658// parameters for parallelogram bounding box659jfloat bx11, by11, bx22, by22;660// parameters for uv texture coordinates of outer parallelogram corners661jfloat ou11, ov11, ou12, ov12, ou21, ov21, ou22, ov22;662// parameters for uv texture coordinates of inner parallelogram corners663jfloat iu11, iv11, iu12, iv12, iu21, iv21, iu22, iv22;664665RETURN_IF_NULL(oglc);666RETURN_IF_NULL(dstOps);667668GET_INVERTED_MATRIX(im, ix11, iy11, ix21, iy21, ix12, iy12,669// inner parallelogram is degenerate670// therefore it encloses no area671// fill outer672OGLRenderer_FillAAParallelogram(oglc, dstOps,673ox11, oy11,674ox21, oy21,675ox12, oy12);676return);677GET_INVERTED_MATRIX(om, ox11, oy11, ox21, oy21, ox12, oy12,678return);679680CHECK_PREVIOUS_OP(OGL_STATE_PGRAM_OP);681682bx11 = bx22 = ox11;683by11 = by22 = oy11;684ADJUST_PGRAM(bx11, ox21, bx22);685ADJUST_PGRAM(by11, oy21, by22);686ADJUST_PGRAM(bx11, ox12, bx22);687ADJUST_PGRAM(by11, oy12, by22);688bx11 = (jfloat) floor(bx11);689by11 = (jfloat) floor(by11);690bx22 = (jfloat) ceil(bx22);691by22 = (jfloat) ceil(by22);692693TRANSFORM(om, ou11, ov11, bx11, by11);694TRANSFORM(om, ou21, ov21, bx22, by11);695TRANSFORM(om, ou12, ov12, bx11, by22);696TRANSFORM(om, ou22, ov22, bx22, by22);697698TRANSFORM(im, iu11, iv11, bx11, by11);699TRANSFORM(im, iu21, iv21, bx22, by11);700TRANSFORM(im, iu12, iv12, bx11, by22);701TRANSFORM(im, iu22, iv22, bx22, by22);702703j2d_glBegin(GL_QUADS);704j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, ou11, ov11);705j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, iu11, iv11);706j2d_glVertex2f(bx11, by11);707j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, ou21, ov21);708j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, iu21, iv21);709j2d_glVertex2f(bx22, by11);710j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, ou22, ov22);711j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, iu22, iv22);712j2d_glVertex2f(bx22, by22);713j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, ou12, ov12);714j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, iu12, iv12);715j2d_glVertex2f(bx11, by22);716j2d_glEnd();717}718719void720OGLRenderer_DrawAAParallelogram(OGLContext *oglc, OGLSDOps *dstOps,721jfloat fx11, jfloat fy11,722jfloat dx21, jfloat dy21,723jfloat dx12, jfloat dy12,724jfloat lwr21, jfloat lwr12)725{726// dx,dy for line width in the "21" and "12" directions.727jfloat ldx21, ldy21, ldx12, ldy12;728// parameters for "outer" parallelogram729jfloat ofx11, ofy11, odx21, ody21, odx12, ody12;730// parameters for "inner" parallelogram731jfloat ifx11, ify11, idx21, idy21, idx12, idy12;732733J2dTraceLn8(J2D_TRACE_INFO,734"OGLRenderer_DrawAAParallelogram "735"(x=%6.2f y=%6.2f "736"dx1=%6.2f dy1=%6.2f lwr1=%6.2f "737"dx2=%6.2f dy2=%6.2f lwr2=%6.2f)",738fx11, fy11,739dx21, dy21, lwr21,740dx12, dy12, lwr12);741742RETURN_IF_NULL(oglc);743RETURN_IF_NULL(dstOps);744745// calculate true dx,dy for line widths from the "line width ratios"746ldx21 = dx21 * lwr21;747ldy21 = dy21 * lwr21;748ldx12 = dx12 * lwr12;749ldy12 = dy12 * lwr12;750751// calculate coordinates of the outer parallelogram752ofx11 = fx11 - (ldx21 + ldx12) / 2.0f;753ofy11 = fy11 - (ldy21 + ldy12) / 2.0f;754odx21 = dx21 + ldx21;755ody21 = dy21 + ldy21;756odx12 = dx12 + ldx12;757ody12 = dy12 + ldy12;758759// Only process the inner parallelogram if the line width ratio760// did not consume the entire interior of the parallelogram761// (i.e. if the width ratio was less than 1.0)762if (lwr21 < 1.0f && lwr12 < 1.0f) {763// calculate coordinates of the inner parallelogram764ifx11 = fx11 + (ldx21 + ldx12) / 2.0f;765ify11 = fy11 + (ldy21 + ldy12) / 2.0f;766idx21 = dx21 - ldx21;767idy21 = dy21 - ldy21;768idx12 = dx12 - ldx12;769idy12 = dy12 - ldy12;770771OGLRenderer_FillAAParallelogramInnerOuter(oglc, dstOps,772ofx11, ofy11,773odx21, ody21,774odx12, ody12,775ifx11, ify11,776idx21, idy21,777idx12, idy12);778} else {779OGLRenderer_FillAAParallelogram(oglc, dstOps,780ofx11, ofy11,781odx21, ody21,782odx12, ody12);783}784}785786void787OGLRenderer_EnableAAParallelogramProgram()788{789J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_EnableAAParallelogramProgram");790791if (aaPgramProgram == 0) {792aaPgramProgram = OGLContext_CreateFragmentProgram(aaPgramShaderSource);793if (aaPgramProgram == 0) {794J2dRlsTraceLn(J2D_TRACE_ERROR,795"OGLRenderer_EnableAAParallelogramProgram: "796"error creating program");797return;798}799}800j2d_glUseProgramObjectARB(aaPgramProgram);801}802803void804OGLRenderer_DisableAAParallelogramProgram()805{806J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_DisableAAParallelogramProgram");807808j2d_glUseProgramObjectARB(0);809}810811#endif /* !HEADLESS */812813814