1/* 2 * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26#ifndef HEADLESS 27 28#include <jlong.h> 29#include <jni_util.h> 30#include <math.h> 31 32#include "sun_java2d_opengl_OGLRenderer.h" 33 34#include "OGLRenderer.h" 35#include "OGLRenderQueue.h" 36#include "OGLSurfaceData.h" 37 38/** 39 * Note: Some of the methods in this file apply a "magic number" 40 * translation to line segments. The OpenGL specification lays out the 41 * "diamond exit rule" for line rasterization, but it is loose enough to 42 * allow for a wide range of line rendering hardware. (It appears that 43 * some hardware, such as the Nvidia GeForce2 series, does not even meet 44 * the spec in all cases.) As such it is difficult to find a mapping 45 * between the Java2D and OpenGL line specs that works consistently across 46 * all hardware combinations. 47 * 48 * Therefore the "magic numbers" you see here have been empirically derived 49 * after testing on a variety of graphics hardware in order to find some 50 * reasonable middle ground between the two specifications. The general 51 * approach is to apply a fractional translation to vertices so that they 52 * hit pixel centers and therefore touch the same pixels as in our other 53 * pipelines. Emphasis was placed on finding values so that OGL lines with 54 * a slope of +/- 1 hit all the same pixels as our other (software) loops. 55 * The stepping in other diagonal lines rendered with OGL may deviate 56 * slightly from those rendered with our software loops, but the most 57 * important thing is that these magic numbers ensure that all OGL lines 58 * hit the same endpoints as our software loops. 59 * 60 * If you find it necessary to change any of these magic numbers in the 61 * future, just be sure that you test the changes across a variety of 62 * hardware to ensure consistent rendering everywhere. 63 */ 64 65void 66OGLRenderer_DrawLine(OGLContext *oglc, jint x1, jint y1, jint x2, jint y2) 67{ 68 J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_DrawLine"); 69 70 RETURN_IF_NULL(oglc); 71 72 CHECK_PREVIOUS_OP(GL_LINES); 73 74 if (y1 == y2) { 75 // horizontal 76 GLfloat fx1 = (GLfloat)x1; 77 GLfloat fx2 = (GLfloat)x2; 78 GLfloat fy = ((GLfloat)y1) + 0.2f; 79 80 if (x1 > x2) { 81 GLfloat t = fx1; fx1 = fx2; fx2 = t; 82 } 83 84 j2d_glVertex2f(fx1+0.2f, fy); 85 j2d_glVertex2f(fx2+1.2f, fy); 86 } else if (x1 == x2) { 87 // vertical 88 GLfloat fx = ((GLfloat)x1) + 0.2f; 89 GLfloat fy1 = (GLfloat)y1; 90 GLfloat fy2 = (GLfloat)y2; 91 92 if (y1 > y2) { 93 GLfloat t = fy1; fy1 = fy2; fy2 = t; 94 } 95 96 j2d_glVertex2f(fx, fy1+0.2f); 97 j2d_glVertex2f(fx, fy2+1.2f); 98 } else { 99 // diagonal 100 GLfloat fx1 = (GLfloat)x1; 101 GLfloat fy1 = (GLfloat)y1; 102 GLfloat fx2 = (GLfloat)x2; 103 GLfloat fy2 = (GLfloat)y2; 104 105 if (x1 < x2) { 106 fx1 += 0.2f; 107 fx2 += 1.0f; 108 } else { 109 fx1 += 0.8f; 110 fx2 -= 0.2f; 111 } 112 113 if (y1 < y2) { 114 fy1 += 0.2f; 115 fy2 += 1.0f; 116 } else { 117 fy1 += 0.8f; 118 fy2 -= 0.2f; 119 } 120 121 j2d_glVertex2f(fx1, fy1); 122 j2d_glVertex2f(fx2, fy2); 123 } 124} 125 126void 127OGLRenderer_DrawRect(OGLContext *oglc, jint x, jint y, jint w, jint h) 128{ 129 J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_DrawRect"); 130 131 if (w < 0 || h < 0) { 132 return; 133 } 134 135 RETURN_IF_NULL(oglc); 136 137 if (w < 2 || h < 2) { 138 // If one dimension is less than 2 then there is no 139 // gap in the middle - draw a solid filled rectangle. 140 CHECK_PREVIOUS_OP(GL_QUADS); 141 GLRECT_BODY_XYWH(x, y, w+1, h+1); 142 } else { 143 GLfloat fx1 = ((GLfloat)x) + 0.2f; 144 GLfloat fy1 = ((GLfloat)y) + 0.2f; 145 GLfloat fx2 = fx1 + ((GLfloat)w); 146 GLfloat fy2 = fy1 + ((GLfloat)h); 147 148 // Avoid drawing the endpoints twice. 149 // Also prefer including the endpoints in the 150 // horizontal sections which draw pixels faster. 151 152 CHECK_PREVIOUS_OP(GL_LINES); 153 // top 154 j2d_glVertex2f(fx1, fy1); 155 j2d_glVertex2f(fx2+1.0f, fy1); 156 // right 157 j2d_glVertex2f(fx2, fy1+1.0f); 158 j2d_glVertex2f(fx2, fy2); 159 // bottom 160 j2d_glVertex2f(fx1, fy2); 161 j2d_glVertex2f(fx2+1.0f, fy2); 162 // left 163 j2d_glVertex2f(fx1, fy1+1.0f); 164 j2d_glVertex2f(fx1, fy2); 165 } 166} 167 168void 169OGLRenderer_DrawPoly(OGLContext *oglc, 170 jint nPoints, jint isClosed, 171 jint transX, jint transY, 172 jint *xPoints, jint *yPoints) 173{ 174 jboolean isEmpty = JNI_TRUE; 175 jint mx, my; 176 jint i; 177 178 J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_DrawPoly"); 179 180 if (xPoints == NULL || yPoints == NULL) { 181 J2dRlsTraceLn(J2D_TRACE_ERROR, 182 "OGLRenderer_DrawPoly: points array is null"); 183 return; 184 } 185 186 RETURN_IF_NULL(oglc); 187 188 // Note that BufferedRenderPipe.drawPoly() has already rejected polys 189 // with nPoints<2, so we can be certain here that we have nPoints>=2. 190 191 mx = xPoints[0]; 192 my = yPoints[0]; 193 194 CHECK_PREVIOUS_OP(GL_LINE_STRIP); 195 for (i = 0; i < nPoints; i++) { 196 jint x = xPoints[i]; 197 jint y = yPoints[i]; 198 199 isEmpty = isEmpty && (x == mx && y == my); 200 201 // Translate each vertex by a fraction so that we hit pixel centers. 202 j2d_glVertex2f((GLfloat)(x + transX) + 0.5f, 203 (GLfloat)(y + transY) + 0.5f); 204 } 205 206 if (isClosed && !isEmpty && 207 (xPoints[nPoints-1] != mx || 208 yPoints[nPoints-1] != my)) 209 { 210 // In this case, the polyline's start and end positions are 211 // different and need to be closed manually; we do this by adding 212 // one more segment back to the starting position. Note that we 213 // do not need to fill in the last pixel (as we do in the following 214 // block) because we are returning to the starting pixel, which 215 // has already been filled in. 216 j2d_glVertex2f((GLfloat)(mx + transX) + 0.5f, 217 (GLfloat)(my + transY) + 0.5f); 218 RESET_PREVIOUS_OP(); // so that we don't leave the line strip open 219 } else if (!isClosed || isEmpty) { 220 // OpenGL omits the last pixel in a polyline, so we fix this by 221 // adding a one-pixel segment at the end. Also, if the polyline 222 // never went anywhere (isEmpty is true), we need to use this 223 // workaround to ensure that a single pixel is touched. 224 CHECK_PREVIOUS_OP(GL_LINES); // this closes the line strip first 225 mx = xPoints[nPoints-1] + transX; 226 my = yPoints[nPoints-1] + transY; 227 j2d_glVertex2i(mx, my); 228 j2d_glVertex2i(mx+1, my+1); 229 // no need for RESET_PREVIOUS_OP, as the line strip is no longer open 230 } else { 231 RESET_PREVIOUS_OP(); // so that we don't leave the line strip open 232 } 233} 234 235JNIEXPORT void JNICALL 236Java_sun_java2d_opengl_OGLRenderer_drawPoly 237 (JNIEnv *env, jobject oglr, 238 jintArray xpointsArray, jintArray ypointsArray, 239 jint nPoints, jboolean isClosed, 240 jint transX, jint transY) 241{ 242 jint *xPoints, *yPoints; 243 244 J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_drawPoly"); 245 246 xPoints = (jint *) 247 (*env)->GetPrimitiveArrayCritical(env, xpointsArray, NULL); 248 if (xPoints != NULL) { 249 yPoints = (jint *) 250 (*env)->GetPrimitiveArrayCritical(env, ypointsArray, NULL); 251 if (yPoints != NULL) { 252 OGLContext *oglc = OGLRenderQueue_GetCurrentContext(); 253 254 OGLRenderer_DrawPoly(oglc, 255 nPoints, isClosed, 256 transX, transY, 257 xPoints, yPoints); 258 259 // 6358147: reset current state, and ensure rendering is 260 // flushed to dest 261 if (oglc != NULL) { 262 RESET_PREVIOUS_OP(); 263 j2d_glFlush(); 264 } 265 266 (*env)->ReleasePrimitiveArrayCritical(env, ypointsArray, yPoints, 267 JNI_ABORT); 268 } 269 (*env)->ReleasePrimitiveArrayCritical(env, xpointsArray, xPoints, 270 JNI_ABORT); 271 } 272} 273 274void 275OGLRenderer_DrawScanlines(OGLContext *oglc, 276 jint scanlineCount, jint *scanlines) 277{ 278 J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_DrawScanlines"); 279 280 RETURN_IF_NULL(oglc); 281 RETURN_IF_NULL(scanlines); 282 283 CHECK_PREVIOUS_OP(GL_LINES); 284 while (scanlineCount > 0) { 285 // Translate each vertex by a fraction so 286 // that we hit pixel centers. 287 GLfloat x1 = ((GLfloat)*(scanlines++)) + 0.2f; 288 GLfloat x2 = ((GLfloat)*(scanlines++)) + 1.2f; 289 GLfloat y = ((GLfloat)*(scanlines++)) + 0.5f; 290 j2d_glVertex2f(x1, y); 291 j2d_glVertex2f(x2, y); 292 scanlineCount--; 293 } 294} 295 296void 297OGLRenderer_FillRect(OGLContext *oglc, jint x, jint y, jint w, jint h) 298{ 299 J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_FillRect"); 300 301 if (w <= 0 || h <= 0) { 302 return; 303 } 304 305 RETURN_IF_NULL(oglc); 306 307 CHECK_PREVIOUS_OP(GL_QUADS); 308 GLRECT_BODY_XYWH(x, y, w, h); 309} 310 311void 312OGLRenderer_FillSpans(OGLContext *oglc, jint spanCount, jint *spans) 313{ 314 J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_FillSpans"); 315 316 RETURN_IF_NULL(oglc); 317 RETURN_IF_NULL(spans); 318 319 CHECK_PREVIOUS_OP(GL_QUADS); 320 while (spanCount > 0) { 321 jint x1 = *(spans++); 322 jint y1 = *(spans++); 323 jint x2 = *(spans++); 324 jint y2 = *(spans++); 325 GLRECT_BODY_XYXY(x1, y1, x2, y2); 326 spanCount--; 327 } 328} 329 330#define FILL_PGRAM(fx11, fy11, dx21, dy21, dx12, dy12) \ 331 do { \ 332 j2d_glVertex2f(fx11, fy11); \ 333 j2d_glVertex2f(fx11 + dx21, fy11 + dy21); \ 334 j2d_glVertex2f(fx11 + dx21 + dx12, fy11 + dy21 + dy12); \ 335 j2d_glVertex2f(fx11 + dx12, fy11 + dy12); \ 336 } while (0) 337 338void 339OGLRenderer_FillParallelogram(OGLContext *oglc, 340 jfloat fx11, jfloat fy11, 341 jfloat dx21, jfloat dy21, 342 jfloat dx12, jfloat dy12) 343{ 344 J2dTraceLn6(J2D_TRACE_INFO, 345 "OGLRenderer_FillParallelogram " 346 "(x=%6.2f y=%6.2f " 347 "dx1=%6.2f dy1=%6.2f " 348 "dx2=%6.2f dy2=%6.2f)", 349 fx11, fy11, 350 dx21, dy21, 351 dx12, dy12); 352 353 RETURN_IF_NULL(oglc); 354 355 CHECK_PREVIOUS_OP(GL_QUADS); 356 357 FILL_PGRAM(fx11, fy11, dx21, dy21, dx12, dy12); 358} 359 360void 361OGLRenderer_DrawParallelogram(OGLContext *oglc, 362 jfloat fx11, jfloat fy11, 363 jfloat dx21, jfloat dy21, 364 jfloat dx12, jfloat dy12, 365 jfloat lwr21, jfloat lwr12) 366{ 367 // dx,dy for line width in the "21" and "12" directions. 368 jfloat ldx21 = dx21 * lwr21; 369 jfloat ldy21 = dy21 * lwr21; 370 jfloat ldx12 = dx12 * lwr12; 371 jfloat ldy12 = dy12 * lwr12; 372 373 // calculate origin of the outer parallelogram 374 jfloat ox11 = fx11 - (ldx21 + ldx12) / 2.0f; 375 jfloat oy11 = fy11 - (ldy21 + ldy12) / 2.0f; 376 377 J2dTraceLn8(J2D_TRACE_INFO, 378 "OGLRenderer_DrawParallelogram " 379 "(x=%6.2f y=%6.2f " 380 "dx1=%6.2f dy1=%6.2f lwr1=%6.2f " 381 "dx2=%6.2f dy2=%6.2f lwr2=%6.2f)", 382 fx11, fy11, 383 dx21, dy21, lwr21, 384 dx12, dy12, lwr12); 385 386 RETURN_IF_NULL(oglc); 387 388 CHECK_PREVIOUS_OP(GL_QUADS); 389 390 // Only need to generate 4 quads if the interior still 391 // has a hole in it (i.e. if the line width ratio was 392 // less than 1.0) 393 if (lwr21 < 1.0f && lwr12 < 1.0f) { 394 // Note: "TOP", "BOTTOM", "LEFT" and "RIGHT" here are 395 // relative to whether the dxNN variables are positive 396 // and negative. The math works fine regardless of 397 // their signs, but for conceptual simplicity the 398 // comments will refer to the sides as if the dxNN 399 // were all positive. "TOP" and "BOTTOM" segments 400 // are defined by the dxy21 deltas. "LEFT" and "RIGHT" 401 // segments are defined by the dxy12 deltas. 402 403 // Each segment includes its starting corner and comes 404 // to just short of the following corner. Thus, each 405 // corner is included just once and the only lengths 406 // needed are the original parallelogram delta lengths 407 // and the "line width deltas". The sides will cover 408 // the following relative territories: 409 // 410 // T T T T T R 411 // L R 412 // L R 413 // L R 414 // L R 415 // L B B B B B 416 417 // TOP segment, to left side of RIGHT edge 418 // "width" of original pgram, "height" of hor. line size 419 fx11 = ox11; 420 fy11 = oy11; 421 FILL_PGRAM(fx11, fy11, dx21, dy21, ldx12, ldy12); 422 423 // RIGHT segment, to top of BOTTOM edge 424 // "width" of vert. line size , "height" of original pgram 425 fx11 = ox11 + dx21; 426 fy11 = oy11 + dy21; 427 FILL_PGRAM(fx11, fy11, ldx21, ldy21, dx12, dy12); 428 429 // BOTTOM segment, from right side of LEFT edge 430 // "width" of original pgram, "height" of hor. line size 431 fx11 = ox11 + dx12 + ldx21; 432 fy11 = oy11 + dy12 + ldy21; 433 FILL_PGRAM(fx11, fy11, dx21, dy21, ldx12, ldy12); 434 435 // LEFT segment, from bottom of TOP edge 436 // "width" of vert. line size , "height" of inner pgram 437 fx11 = ox11 + ldx12; 438 fy11 = oy11 + ldy12; 439 FILL_PGRAM(fx11, fy11, ldx21, ldy21, dx12, dy12); 440 } else { 441 // The line width ratios were large enough to consume 442 // the entire hole in the middle of the parallelogram 443 // so we can just issue one large quad for the outer 444 // parallelogram. 445 dx21 += ldx21; 446 dy21 += ldy21; 447 dx12 += ldx12; 448 dy12 += ldy12; 449 FILL_PGRAM(ox11, oy11, dx21, dy21, dx12, dy12); 450 } 451} 452 453static GLhandleARB aaPgramProgram = 0; 454 455/* 456 * This shader fills the space between an outer and inner parallelogram. 457 * It can be used to draw an outline by specifying both inner and outer 458 * values. It fills pixels by estimating what portion falls inside the 459 * outer shape, and subtracting an estimate of what portion falls inside 460 * the inner shape. Specifying both inner and outer values produces a 461 * standard "wide outline". Specifying an inner shape that falls far 462 * outside the outer shape allows the same shader to fill the outer 463 * shape entirely since pixels that fall within the outer shape are never 464 * inside the inner shape and so they are filled based solely on their 465 * coverage of the outer shape. 466 * 467 * The setup code renders this shader over the bounds of the outer 468 * shape (or the only shape in the case of a fill operation) and 469 * sets the texture 0 coordinates so that 0,0=>0,1=>1,1=>1,0 in those 470 * texture coordinates map to the four corners of the parallelogram. 471 * Similarly the texture 1 coordinates map the inner shape to the 472 * unit square as well, but in a different coordinate system. 473 * 474 * When viewed in the texture coordinate systems the parallelograms 475 * we are filling are unit squares, but the pixels have then become 476 * tiny parallelograms themselves. Both of the texture coordinate 477 * systems are affine transforms so the rate of change in X and Y 478 * of the texture coordinates are essentially constants and happen 479 * to correspond to the size and direction of the slanted sides of 480 * the distorted pixels relative to the "square mapped" boundary 481 * of the parallelograms. 482 * 483 * The shader uses the dFdx() and dFdy() functions to measure the "rate 484 * of change" of these texture coordinates and thus gets an accurate 485 * measure of the size and shape of a pixel relative to the two 486 * parallelograms. It then uses the bounds of the size and shape 487 * of a pixel to intersect with the unit square to estimate the 488 * coverage of the pixel. Unfortunately, without a lot more work 489 * to calculate the exact area of intersection between a unit 490 * square (the original parallelogram) and a parallelogram (the 491 * distorted pixel), this shader only approximates the pixel 492 * coverage, but emperically the estimate is very useful and 493 * produces visually pleasing results, if not theoretically accurate. 494 */ 495static const char *aaPgramShaderSource = 496 "void main() {" 497 // Calculate the vectors for the "legs" of the pixel parallelogram 498 // for the outer parallelogram. 499 " vec2 oleg1 = dFdx(gl_TexCoord[0].st);" 500 " vec2 oleg2 = dFdy(gl_TexCoord[0].st);" 501 // Calculate the bounds of the distorted pixel parallelogram. 502 " vec2 corner = gl_TexCoord[0].st - (oleg1+oleg2)/2.0;" 503 " vec2 omin = min(corner, corner+oleg1);" 504 " omin = min(omin, corner+oleg2);" 505 " omin = min(omin, corner+oleg1+oleg2);" 506 " vec2 omax = max(corner, corner+oleg1);" 507 " omax = max(omax, corner+oleg2);" 508 " omax = max(omax, corner+oleg1+oleg2);" 509 // Calculate the vectors for the "legs" of the pixel parallelogram 510 // for the inner parallelogram. 511 " vec2 ileg1 = dFdx(gl_TexCoord[1].st);" 512 " vec2 ileg2 = dFdy(gl_TexCoord[1].st);" 513 // Calculate the bounds of the distorted pixel parallelogram. 514 " corner = gl_TexCoord[1].st - (ileg1+ileg2)/2.0;" 515 " vec2 imin = min(corner, corner+ileg1);" 516 " imin = min(imin, corner+ileg2);" 517 " imin = min(imin, corner+ileg1+ileg2);" 518 " vec2 imax = max(corner, corner+ileg1);" 519 " imax = max(imax, corner+ileg2);" 520 " imax = max(imax, corner+ileg1+ileg2);" 521 // Clamp the bounds of the parallelograms to the unit square to 522 // estimate the intersection of the pixel parallelogram with 523 // the unit square. The ratio of the 2 rectangle areas is a 524 // reasonable estimate of the proportion of coverage. 525 " vec2 o1 = clamp(omin, 0.0, 1.0);" 526 " vec2 o2 = clamp(omax, 0.0, 1.0);" 527 " float oint = (o2.y-o1.y)*(o2.x-o1.x);" 528 " float oarea = (omax.y-omin.y)*(omax.x-omin.x);" 529 " vec2 i1 = clamp(imin, 0.0, 1.0);" 530 " vec2 i2 = clamp(imax, 0.0, 1.0);" 531 " float iint = (i2.y-i1.y)*(i2.x-i1.x);" 532 " float iarea = (imax.y-imin.y)*(imax.x-imin.x);" 533 // Proportion of pixel in outer shape minus the proportion 534 // of pixel in the inner shape == the coverage of the pixel 535 // in the area between the two. 536 " float coverage = oint/oarea - iint / iarea;" 537 " gl_FragColor = gl_Color * coverage;" 538 "}"; 539 540#define ADJUST_PGRAM(V1, DV, V2) \ 541 do { \ 542 if ((DV) >= 0) { \ 543 (V2) += (DV); \ 544 } else { \ 545 (V1) += (DV); \ 546 } \ 547 } while (0) 548 549// Invert the following transform: 550// DeltaT(0, 0) == (0, 0) 551// DeltaT(1, 0) == (DX1, DY1) 552// DeltaT(0, 1) == (DX2, DY2) 553// DeltaT(1, 1) == (DX1+DX2, DY1+DY2) 554// TM00 = DX1, TM01 = DX2, (TM02 = X11) 555// TM10 = DY1, TM11 = DY2, (TM12 = Y11) 556// Determinant = TM00*TM11 - TM01*TM10 557// = DX1*DY2 - DX2*DY1 558// Inverse is: 559// IM00 = TM11/det, IM01 = -TM01/det 560// IM10 = -TM10/det, IM11 = TM00/det 561// IM02 = (TM01 * TM12 - TM11 * TM02) / det, 562// IM12 = (TM10 * TM02 - TM00 * TM12) / det, 563 564#define DECLARE_MATRIX(MAT) \ 565 jfloat MAT ## 00, MAT ## 01, MAT ## 02, MAT ## 10, MAT ## 11, MAT ## 12 566 567#define GET_INVERTED_MATRIX(MAT, X11, Y11, DX1, DY1, DX2, DY2, RET_CODE) \ 568 do { \ 569 jfloat det = DX1*DY2 - DX2*DY1; \ 570 if (det == 0) { \ 571 RET_CODE; \ 572 } \ 573 MAT ## 00 = DY2/det; \ 574 MAT ## 01 = -DX2/det; \ 575 MAT ## 10 = -DY1/det; \ 576 MAT ## 11 = DX1/det; \ 577 MAT ## 02 = (DX2 * Y11 - DY2 * X11) / det; \ 578 MAT ## 12 = (DY1 * X11 - DX1 * Y11) / det; \ 579 } while (0) 580 581#define TRANSFORM(MAT, TX, TY, X, Y) \ 582 do { \ 583 TX = (X) * MAT ## 00 + (Y) * MAT ## 01 + MAT ## 02; \ 584 TY = (X) * MAT ## 10 + (Y) * MAT ## 11 + MAT ## 12; \ 585 } while (0) 586 587void 588OGLRenderer_FillAAParallelogram(OGLContext *oglc, OGLSDOps *dstOps, 589 jfloat fx11, jfloat fy11, 590 jfloat dx21, jfloat dy21, 591 jfloat dx12, jfloat dy12) 592{ 593 DECLARE_MATRIX(om); 594 // parameters for parallelogram bounding box 595 jfloat bx11, by11, bx22, by22; 596 // parameters for uv texture coordinates of parallelogram corners 597 jfloat u11, v11, u12, v12, u21, v21, u22, v22; 598 599 J2dTraceLn6(J2D_TRACE_INFO, 600 "OGLRenderer_FillAAParallelogram " 601 "(x=%6.2f y=%6.2f " 602 "dx1=%6.2f dy1=%6.2f " 603 "dx2=%6.2f dy2=%6.2f)", 604 fx11, fy11, 605 dx21, dy21, 606 dx12, dy12); 607 608 RETURN_IF_NULL(oglc); 609 RETURN_IF_NULL(dstOps); 610 611 GET_INVERTED_MATRIX(om, fx11, fy11, dx21, dy21, dx12, dy12, 612 return); 613 614 CHECK_PREVIOUS_OP(OGL_STATE_PGRAM_OP); 615 616 bx11 = bx22 = fx11; 617 by11 = by22 = fy11; 618 ADJUST_PGRAM(bx11, dx21, bx22); 619 ADJUST_PGRAM(by11, dy21, by22); 620 ADJUST_PGRAM(bx11, dx12, bx22); 621 ADJUST_PGRAM(by11, dy12, by22); 622 bx11 = (jfloat) floor(bx11); 623 by11 = (jfloat) floor(by11); 624 bx22 = (jfloat) ceil(bx22); 625 by22 = (jfloat) ceil(by22); 626 627 TRANSFORM(om, u11, v11, bx11, by11); 628 TRANSFORM(om, u21, v21, bx22, by11); 629 TRANSFORM(om, u12, v12, bx11, by22); 630 TRANSFORM(om, u22, v22, bx22, by22); 631 632 j2d_glBegin(GL_QUADS); 633 j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u11, v11); 634 j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 5.f, 5.f); 635 j2d_glVertex2f(bx11, by11); 636 j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u21, v21); 637 j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 6.f, 5.f); 638 j2d_glVertex2f(bx22, by11); 639 j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u22, v22); 640 j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 6.f, 6.f); 641 j2d_glVertex2f(bx22, by22); 642 j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u12, v12); 643 j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 5.f, 6.f); 644 j2d_glVertex2f(bx11, by22); 645 j2d_glEnd(); 646} 647 648void 649OGLRenderer_FillAAParallelogramInnerOuter(OGLContext *oglc, OGLSDOps *dstOps, 650 jfloat ox11, jfloat oy11, 651 jfloat ox21, jfloat oy21, 652 jfloat ox12, jfloat oy12, 653 jfloat ix11, jfloat iy11, 654 jfloat ix21, jfloat iy21, 655 jfloat ix12, jfloat iy12) 656{ 657 DECLARE_MATRIX(om); 658 DECLARE_MATRIX(im); 659 // parameters for parallelogram bounding box 660 jfloat bx11, by11, bx22, by22; 661 // parameters for uv texture coordinates of outer parallelogram corners 662 jfloat ou11, ov11, ou12, ov12, ou21, ov21, ou22, ov22; 663 // parameters for uv texture coordinates of inner parallelogram corners 664 jfloat iu11, iv11, iu12, iv12, iu21, iv21, iu22, iv22; 665 666 RETURN_IF_NULL(oglc); 667 RETURN_IF_NULL(dstOps); 668 669 GET_INVERTED_MATRIX(im, ix11, iy11, ix21, iy21, ix12, iy12, 670 // inner parallelogram is degenerate 671 // therefore it encloses no area 672 // fill outer 673 OGLRenderer_FillAAParallelogram(oglc, dstOps, 674 ox11, oy11, 675 ox21, oy21, 676 ox12, oy12); 677 return); 678 GET_INVERTED_MATRIX(om, ox11, oy11, ox21, oy21, ox12, oy12, 679 return); 680 681 CHECK_PREVIOUS_OP(OGL_STATE_PGRAM_OP); 682 683 bx11 = bx22 = ox11; 684 by11 = by22 = oy11; 685 ADJUST_PGRAM(bx11, ox21, bx22); 686 ADJUST_PGRAM(by11, oy21, by22); 687 ADJUST_PGRAM(bx11, ox12, bx22); 688 ADJUST_PGRAM(by11, oy12, by22); 689 bx11 = (jfloat) floor(bx11); 690 by11 = (jfloat) floor(by11); 691 bx22 = (jfloat) ceil(bx22); 692 by22 = (jfloat) ceil(by22); 693 694 TRANSFORM(om, ou11, ov11, bx11, by11); 695 TRANSFORM(om, ou21, ov21, bx22, by11); 696 TRANSFORM(om, ou12, ov12, bx11, by22); 697 TRANSFORM(om, ou22, ov22, bx22, by22); 698 699 TRANSFORM(im, iu11, iv11, bx11, by11); 700 TRANSFORM(im, iu21, iv21, bx22, by11); 701 TRANSFORM(im, iu12, iv12, bx11, by22); 702 TRANSFORM(im, iu22, iv22, bx22, by22); 703 704 j2d_glBegin(GL_QUADS); 705 j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, ou11, ov11); 706 j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, iu11, iv11); 707 j2d_glVertex2f(bx11, by11); 708 j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, ou21, ov21); 709 j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, iu21, iv21); 710 j2d_glVertex2f(bx22, by11); 711 j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, ou22, ov22); 712 j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, iu22, iv22); 713 j2d_glVertex2f(bx22, by22); 714 j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, ou12, ov12); 715 j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, iu12, iv12); 716 j2d_glVertex2f(bx11, by22); 717 j2d_glEnd(); 718} 719 720void 721OGLRenderer_DrawAAParallelogram(OGLContext *oglc, OGLSDOps *dstOps, 722 jfloat fx11, jfloat fy11, 723 jfloat dx21, jfloat dy21, 724 jfloat dx12, jfloat dy12, 725 jfloat lwr21, jfloat lwr12) 726{ 727 // dx,dy for line width in the "21" and "12" directions. 728 jfloat ldx21, ldy21, ldx12, ldy12; 729 // parameters for "outer" parallelogram 730 jfloat ofx11, ofy11, odx21, ody21, odx12, ody12; 731 // parameters for "inner" parallelogram 732 jfloat ifx11, ify11, idx21, idy21, idx12, idy12; 733 734 J2dTraceLn8(J2D_TRACE_INFO, 735 "OGLRenderer_DrawAAParallelogram " 736 "(x=%6.2f y=%6.2f " 737 "dx1=%6.2f dy1=%6.2f lwr1=%6.2f " 738 "dx2=%6.2f dy2=%6.2f lwr2=%6.2f)", 739 fx11, fy11, 740 dx21, dy21, lwr21, 741 dx12, dy12, lwr12); 742 743 RETURN_IF_NULL(oglc); 744 RETURN_IF_NULL(dstOps); 745 746 // calculate true dx,dy for line widths from the "line width ratios" 747 ldx21 = dx21 * lwr21; 748 ldy21 = dy21 * lwr21; 749 ldx12 = dx12 * lwr12; 750 ldy12 = dy12 * lwr12; 751 752 // calculate coordinates of the outer parallelogram 753 ofx11 = fx11 - (ldx21 + ldx12) / 2.0f; 754 ofy11 = fy11 - (ldy21 + ldy12) / 2.0f; 755 odx21 = dx21 + ldx21; 756 ody21 = dy21 + ldy21; 757 odx12 = dx12 + ldx12; 758 ody12 = dy12 + ldy12; 759 760 // Only process the inner parallelogram if the line width ratio 761 // did not consume the entire interior of the parallelogram 762 // (i.e. if the width ratio was less than 1.0) 763 if (lwr21 < 1.0f && lwr12 < 1.0f) { 764 // calculate coordinates of the inner parallelogram 765 ifx11 = fx11 + (ldx21 + ldx12) / 2.0f; 766 ify11 = fy11 + (ldy21 + ldy12) / 2.0f; 767 idx21 = dx21 - ldx21; 768 idy21 = dy21 - ldy21; 769 idx12 = dx12 - ldx12; 770 idy12 = dy12 - ldy12; 771 772 OGLRenderer_FillAAParallelogramInnerOuter(oglc, dstOps, 773 ofx11, ofy11, 774 odx21, ody21, 775 odx12, ody12, 776 ifx11, ify11, 777 idx21, idy21, 778 idx12, idy12); 779 } else { 780 OGLRenderer_FillAAParallelogram(oglc, dstOps, 781 ofx11, ofy11, 782 odx21, ody21, 783 odx12, ody12); 784 } 785} 786 787void 788OGLRenderer_EnableAAParallelogramProgram() 789{ 790 J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_EnableAAParallelogramProgram"); 791 792 if (aaPgramProgram == 0) { 793 aaPgramProgram = OGLContext_CreateFragmentProgram(aaPgramShaderSource); 794 if (aaPgramProgram == 0) { 795 J2dRlsTraceLn(J2D_TRACE_ERROR, 796 "OGLRenderer_EnableAAParallelogramProgram: " 797 "error creating program"); 798 return; 799 } 800 } 801 j2d_glUseProgramObjectARB(aaPgramProgram); 802} 803 804void 805OGLRenderer_DisableAAParallelogramProgram() 806{ 807 J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_DisableAAParallelogramProgram"); 808 809 j2d_glUseProgramObjectARB(0); 810} 811 812#endif /* !HEADLESS */ 813