1 /* 2 * Copyright (c) 2019, 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_metal_MTLRenderer.h" 33 34 #include "MTLRenderer.h" 35 #include "MTLRenderQueue.h" 36 #include "MTLSurfaceData.h" 37 #include "MTLUtils.h" 38 #import "MTLLayer.h" 39 40 /** 41 * Note: Some of the methods in this file apply a "magic number" 42 * translation to line segments. The OpenGL specification lays out the 43 * "diamond exit rule" for line rasterization, but it is loose enough to 44 * allow for a wide range of line rendering hardware. (It appears that 45 * some hardware, such as the Nvidia GeForce2 series, does not even meet 46 * the spec in all cases.) As such it is difficult to find a mapping 47 * between the Java2D and OpenGL line specs that works consistently across 48 * all hardware combinations. 49 * 50 * Therefore the "magic numbers" you see here have been empirically derived 51 * after testing on a variety of graphics hardware in order to find some 52 * reasonable middle ground between the two specifications. The general 53 * approach is to apply a fractional translation to vertices so that they 54 * hit pixel centers and therefore touch the same pixels as in our other 55 * pipelines. Emphasis was placed on finding values so that MTL lines with 56 * a slope of +/- 1 hit all the same pixels as our other (software) loops. 57 * The stepping in other diagonal lines rendered with MTL may deviate 58 * slightly from those rendered with our software loops, but the most 59 * important thing is that these magic numbers ensure that all MTL lines 60 * hit the same endpoints as our software loops. 61 * 62 * If you find it necessary to change any of these magic numbers in the 63 * future, just be sure that you test the changes across a variety of 64 * hardware to ensure consistent rendering everywhere. 65 */ 66 67 void MTLRenderer_DrawLine(MTLContext *mtlc, BMTLSDOps * dstOps, jint x1, jint y1, jint x2, jint y2) { 68 if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) { 69 J2dTraceLn(J2D_TRACE_ERROR, "MTLRenderer_DrawLine: dest is null"); 70 return; 71 } 72 73 J2dTraceLn5(J2D_TRACE_INFO, "MTLRenderer_DrawLine (x1=%1.2f y1=%1.2f x2=%1.2f y2=%1.2f), dst tex=%p", x1, y1, x2, y2, dstOps->pTexture); 74 75 id<MTLRenderCommandEncoder> mtlEncoder = [mtlc createRenderEncoderForDest:dstOps->pTexture]; 76 if (mtlEncoder == nil) 77 return; 78 79 struct Vertex verts[2] = { 80 {{x1, y1, 0.0}}, 81 {{x2, y2, 0.0}} 82 }; 83 84 [mtlEncoder setVertexBytes:verts length:sizeof(verts) atIndex:MeshVertexBuffer]; 85 [mtlEncoder drawPrimitives:MTLPrimitiveTypeLine vertexStart:0 vertexCount:2]; 86 [mtlEncoder endEncoding]; 87 } 88 89 void MTLRenderer_DrawRect(MTLContext *mtlc, BMTLSDOps * dstOps, jint x, jint y, jint w, jint h) { 90 if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) { 91 J2dTraceLn(J2D_TRACE_ERROR, "MTLRenderer_DrawRect: dest is null"); 92 return; 93 } 94 95 id<MTLTexture> dest = dstOps->pTexture; 96 J2dTraceLn5(J2D_TRACE_INFO, "MTLRenderer_DrawRect (x=%d y=%d w=%d h=%d), dst tex=%p", x, y, w, h, dest); 97 98 // TODO: use DrawParallelogram(x, y, w, h, lw=1, lh=1) 99 id<MTLRenderCommandEncoder> mtlEncoder = [mtlc createRenderEncoderForDest:dest]; 100 if (mtlEncoder == nil) 101 return; 102 103 const int verticesCount = 5; 104 struct Vertex vertices[5] = { 105 {{x, y, 0.0}}, 106 {{x + w, y, 0.0}}, 107 {{x + w, y + h, 0.0}}, 108 {{x, y + h, 0.0}}, 109 {{x, y, 0.0}}, 110 }; 111 [mtlEncoder setVertexBytes:vertices length:sizeof(vertices) atIndex:MeshVertexBuffer]; 112 [mtlEncoder drawPrimitives:MTLPrimitiveTypeLineStrip vertexStart:0 vertexCount:verticesCount]; 113 [mtlEncoder endEncoding]; 114 } 115 116 const int POLYLINE_BUF_SIZE = 64; 117 118 static void fillVertex(struct Vertex * vertex, int x, int y) { 119 vertex->position[0] = x; 120 vertex->position[1] = y; 121 vertex->position[2] = 0; 122 } 123 124 void MTLRenderer_DrawPoly(MTLContext *mtlc, BMTLSDOps * dstOps, 125 jint nPoints, jint isClosed, 126 jint transX, jint transY, 127 jint *xPoints, jint *yPoints) 128 { 129 // Note that BufferedRenderPipe.drawPoly() has already rejected polys 130 // with nPoints<2, so we can be certain here that we have nPoints>=2. 131 if (xPoints == NULL || yPoints == NULL || nPoints < 2) { // just for insurance 132 J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_DrawPoly: points array is empty"); 133 return; 134 } 135 136 if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) { 137 J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_DrawPoly: dest is null"); 138 return; 139 } 140 141 J2dTraceLn4(J2D_TRACE_INFO, "MTLRenderer_DrawPoly: %d points, transX=%d, transY=%d, dst tex=%p", nPoints, transX, transY, dstOps->pTexture); 142 143 __block struct { 144 struct Vertex verts[POLYLINE_BUF_SIZE]; 145 } pointsChunk; 146 147 jint prevX = *(xPoints++); 148 jint prevY = *(yPoints++); 149 --nPoints; 150 const jint firstX = prevX; 151 const jint firstY = prevY; 152 while (nPoints > 0) { 153 fillVertex(pointsChunk.verts, prevX + transX, prevY + transY); 154 155 const bool isLastChunk = nPoints + 1 <= POLYLINE_BUF_SIZE; 156 __block int chunkSize = isLastChunk ? nPoints : POLYLINE_BUF_SIZE - 1; 157 158 for (int i = 1; i < chunkSize; i++) { 159 prevX = *(xPoints++); 160 prevY = *(yPoints++); 161 fillVertex(pointsChunk.verts + i, prevX + transX, prevY + transY); 162 } 163 164 bool drawCloseSegment = false; 165 if (isClosed && isLastChunk) { 166 if (chunkSize + 2 <= POLYLINE_BUF_SIZE) { 167 fillVertex(pointsChunk.verts + chunkSize, firstX + transX, firstY + transY); 168 ++chunkSize; 169 } else 170 drawCloseSegment = true; 171 } 172 173 nPoints -= chunkSize; 174 id<MTLRenderCommandEncoder> mtlEncoder = [mtlc createRenderEncoderForDest:dstOps->pTexture]; 175 if (mtlEncoder == nil) 176 return; 177 178 [mtlEncoder setVertexBytes:pointsChunk.verts length:sizeof(pointsChunk.verts) atIndex:MeshVertexBuffer]; 179 [mtlEncoder drawPrimitives:MTLPrimitiveTypeLineStrip vertexStart:0 vertexCount:chunkSize + 1]; 180 if (drawCloseSegment) { 181 struct Vertex vertices[2] = { 182 {{prevX + transX, prevY + transY, 0.0}}, 183 {{firstX + transX, firstY + transY, 0.0}}, 184 }; 185 [mtlEncoder setVertexBytes:vertices length:sizeof(vertices) atIndex:MeshVertexBuffer]; 186 [mtlEncoder drawPrimitives:MTLPrimitiveTypeLine vertexStart:0 vertexCount:2]; 187 } 188 189 [mtlEncoder endEncoding]; 190 } 191 } 192 193 JNIEXPORT void JNICALL 194 Java_sun_java2d_metal_MTLRenderer_drawPoly 195 (JNIEnv *env, jobject mtlr, 196 jintArray xpointsArray, jintArray ypointsArray, 197 jint nPoints, jboolean isClosed, 198 jint transX, jint transY) 199 { 200 jint *xPoints, *yPoints; 201 //TODO 202 J2dTraceNotImplPrimitive("MTLRenderer_drawPoly"); 203 J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_drawPoly"); 204 } 205 206 void 207 MTLRenderer_DrawScanlines(MTLContext *mtlc, BMTLSDOps * dstOps, 208 jint scanlineCount, jint *scanlines) 209 { 210 //TODO 211 J2dTraceNotImplPrimitive("MTLRenderer_DrawScanlines"); 212 J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_DrawScanlines"); 213 } 214 215 void 216 MTLRenderer_FillRect(MTLContext *mtlc, BMTLSDOps * dstOps, jint x, jint y, jint w, jint h) 217 { 218 J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_FillRect"); 219 220 if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) { 221 J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_FillRect: current dest is null"); 222 return; 223 } 224 225 struct Vertex verts[PGRAM_VERTEX_COUNT] = { 226 { {x, y, 0.0}}, 227 { {x, y+h, 0.0}}, 228 { {x+w, y+h, 0.0}}, 229 { {x+w, y+h, 0.0}}, 230 { {x+w, y, 0.0}}, 231 { {x, y, 0.0}, 232 }}; 233 234 235 id<MTLTexture> dest = dstOps->pTexture; 236 J2dTraceLn5(J2D_TRACE_INFO, "MTLRenderer_FillRect (x=%d y=%d w=%d h=%d), dst tex=%p", x, y, w, h, dest); 237 238 // Encode render command. 239 id<MTLRenderCommandEncoder> mtlEncoder = [mtlc createRenderEncoderForDest:dest]; 240 if (mtlEncoder == nil) 241 return; 242 243 [mtlEncoder setVertexBytes:verts length:sizeof(verts) atIndex:MeshVertexBuffer]; 244 [mtlEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount: PGRAM_VERTEX_COUNT]; 245 [mtlEncoder endEncoding]; 246 } 247 248 const int SPAN_BUF_SIZE=64; 249 250 void 251 MTLRenderer_FillSpans(MTLContext *mtlc, BMTLSDOps * dstOps, jint spanCount, jint *spans) 252 { 253 J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_FillSpans"); 254 if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) { 255 J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_FillSpans: dest is null"); 256 return; 257 } 258 259 while (spanCount > 0) { 260 __block struct { 261 jfloat spns[SPAN_BUF_SIZE*4]; 262 } spanStruct; 263 264 __block jfloat sc = spanCount > SPAN_BUF_SIZE ? SPAN_BUF_SIZE : spanCount; 265 266 for (int i = 0; i < sc; i++) { 267 spanStruct.spns[i * 4] = *(spans++); 268 spanStruct.spns[i * 4 + 1] = *(spans++); 269 spanStruct.spns[i * 4 + 2] = *(spans++); 270 spanStruct.spns[i * 4 + 3] = *(spans++); 271 } 272 273 spanCount -= sc; 274 275 id<MTLTexture> dest = dstOps->pTexture; 276 id<MTLRenderCommandEncoder> mtlEncoder = [mtlc createRenderEncoderForDest:dest]; 277 if (mtlEncoder == nil) 278 return; 279 280 for (int i = 0; i < sc; i++) { 281 jfloat x1 = spanStruct.spns[i * 4]; 282 jfloat y1 = spanStruct.spns[i * 4 + 1]; 283 jfloat x2 = spanStruct.spns[i * 4 + 2]; 284 jfloat y2 = spanStruct.spns[i * 4 + 3]; 285 286 struct Vertex verts[PGRAM_VERTEX_COUNT] = { 287 {{x1, y1, 0.0}}, 288 {{x2, y1, 0.0}}, 289 {{x1, y2, 0.0}}, 290 {{x2, y1, 0.0}}, 291 {{x2, y2, 0.0}}, 292 {{x1, y2, 0.0}, 293 }}; 294 295 [mtlEncoder setVertexBytes:verts length:sizeof(verts) atIndex:MeshVertexBuffer]; 296 [mtlEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:PGRAM_VERTEX_COUNT]; 297 } 298 299 [mtlEncoder endEncoding]; 300 [mtlEncoder release]; 301 } 302 } 303 304 void 305 MTLRenderer_FillParallelogram(MTLContext *mtlc, BMTLSDOps * dstOps, 306 jfloat fx11, jfloat fy11, 307 jfloat dx21, jfloat dy21, 308 jfloat dx12, jfloat dy12) 309 { 310 J2dTracePrimitive("MTLRenderer_FillParallelogram"); 311 312 if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) { 313 J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_FillParallelogram: current dest is null"); 314 return; 315 } 316 317 id<MTLTexture> dest = dstOps->pTexture; 318 J2dTraceLn7(J2D_TRACE_INFO, 319 "MTLRenderer_FillParallelogram " 320 "(x=%6.2f y=%6.2f " 321 "dx1=%6.2f dy1=%6.2f " 322 "dx2=%6.2f dy2=%6.2f dst tex=%p)", 323 fx11, fy11, 324 dx21, dy21, 325 dx12, dy12, dest); 326 327 struct Vertex verts[PGRAM_VERTEX_COUNT] = { 328 { {fx11, fy11, 0.0}}, 329 { {fx11+dx21, fy11+dy21, 0.0}}, 330 { {fx11+dx12, fy11+dy12, 0.0}}, 331 { {fx11+dx21, fy11+dy21, 0.0}}, 332 { {fx11 + dx21 + dx12, fy11+ dy21 + dy12, 0.0}}, 333 { {fx11+dx12, fy11+dy12, 0.0}, 334 }}; 335 336 // Encode render command. 337 id<MTLRenderCommandEncoder> mtlEncoder = [mtlc createRenderEncoderForDest:dest]; 338 if (mtlEncoder == nil) 339 return; 340 341 [mtlEncoder setVertexBytes:verts length:sizeof(verts) atIndex:MeshVertexBuffer]; 342 [mtlEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount: PGRAM_VERTEX_COUNT]; 343 [mtlEncoder endEncoding]; 344 } 345 346 void 347 MTLRenderer_DrawParallelogram(MTLContext *mtlc, BMTLSDOps * dstOps, 348 jfloat fx11, jfloat fy11, 349 jfloat dx21, jfloat dy21, 350 jfloat dx12, jfloat dy12, 351 jfloat lwr21, jfloat lwr12) 352 { 353 J2dTraceNotImplPrimitive("MTLRenderer_DrawParallelogram"); 354 // dx,dy for line width in the "21" and "12" directions. 355 jfloat ldx21 = dx21 * lwr21; 356 jfloat ldy21 = dy21 * lwr21; 357 jfloat ldx12 = dx12 * lwr12; 358 jfloat ldy12 = dy12 * lwr12; 359 360 // calculate origin of the outer parallelogram 361 jfloat ox11 = fx11 - (ldx21 + ldx12) / 2.0f; 362 jfloat oy11 = fy11 - (ldy21 + ldy12) / 2.0f; 363 364 J2dTraceLn8(J2D_TRACE_INFO, 365 "MTLRenderer_DrawParallelogram " 366 "(x=%6.2f y=%6.2f " 367 "dx1=%6.2f dy1=%6.2f lwr1=%6.2f " 368 "dx2=%6.2f dy2=%6.2f lwr2=%6.2f)", 369 fx11, fy11, 370 dx21, dy21, lwr21, 371 dx12, dy12, lwr12); 372 373 374 // Only need to generate 4 quads if the interior still 375 // has a hole in it (i.e. if the line width ratio was 376 // less than 1.0) 377 if (lwr21 < 1.0f && lwr12 < 1.0f) { 378 379 // Note: "TOP", "BOTTOM", "LEFT" and "RIGHT" here are 380 // relative to whether the dxNN variables are positive 381 // and negative. The math works fine regardless of 382 // their signs, but for conceptual simplicity the 383 // comments will refer to the sides as if the dxNN 384 // were all positive. "TOP" and "BOTTOM" segments 385 // are defined by the dxy21 deltas. "LEFT" and "RIGHT" 386 // segments are defined by the dxy12 deltas. 387 388 // Each segment includes its starting corner and comes 389 // to just short of the following corner. Thus, each 390 // corner is included just once and the only lengths 391 // needed are the original parallelogram delta lengths 392 // and the "line width deltas". The sides will cover 393 // the following relative territories: 394 // 395 // T T T T T R 396 // L R 397 // L R 398 // L R 399 // L R 400 // L B B B B B 401 402 // TOP segment, to left side of RIGHT edge 403 // "width" of original pgram, "height" of hor. line size 404 fx11 = ox11; 405 fy11 = oy11; 406 MTLRenderer_FillParallelogram(mtlc, dstOps, fx11, fy11, dx21, dy21, ldx12, ldy12); 407 408 // RIGHT segment, to top of BOTTOM edge 409 // "width" of vert. line size , "height" of original pgram 410 fx11 = ox11 + dx21; 411 fy11 = oy11 + dy21; 412 MTLRenderer_FillParallelogram(mtlc, dstOps, fx11, fy11, ldx21, ldy21, dx12, dy12); 413 414 // BOTTOM segment, from right side of LEFT edge 415 // "width" of original pgram, "height" of hor. line size 416 fx11 = ox11 + dx12 + ldx21; 417 fy11 = oy11 + dy12 + ldy21; 418 MTLRenderer_FillParallelogram(mtlc, dstOps, fx11, fy11, dx21, dy21, ldx12, ldy12); 419 420 // LEFT segment, from bottom of TOP edge 421 // "width" of vert. line size , "height" of inner pgram 422 fx11 = ox11 + ldx12; 423 fy11 = oy11 + ldy12; 424 MTLRenderer_FillParallelogram(mtlc, dstOps, fx11, fy11, ldx21, ldy21, dx12, dy12); 425 } else { 426 // The line width ratios were large enough to consume 427 // the entire hole in the middle of the parallelogram 428 // so we can just issue one large quad for the outer 429 // parallelogram. 430 dx21 += ldx21; 431 dy21 += ldy21; 432 dx12 += ldx12; 433 dy12 += ldy12; 434 MTLRenderer_FillParallelogram(mtlc, dstOps, ox11, oy11, dx21, dy21, dx12, dy12); 435 } 436 } 437 438 439 static GLhandleARB aaPgramProgram = 0; 440 441 /* 442 * This shader fills the space between an outer and inner parallelogram. 443 * It can be used to draw an outline by specifying both inner and outer 444 * values. It fills pixels by estimating what portion falls inside the 445 * outer shape, and subtracting an estimate of what portion falls inside 446 * the inner shape. Specifying both inner and outer values produces a 447 * standard "wide outline". Specifying an inner shape that falls far 448 * outside the outer shape allows the same shader to fill the outer 449 * shape entirely since pixels that fall within the outer shape are never 450 * inside the inner shape and so they are filled based solely on their 451 * coverage of the outer shape. 452 * 453 * The setup code renders this shader over the bounds of the outer 454 * shape (or the only shape in the case of a fill operation) and 455 * sets the texture 0 coordinates so that 0,0=>0,1=>1,1=>1,0 in those 456 * texture coordinates map to the four corners of the parallelogram. 457 * Similarly the texture 1 coordinates map the inner shape to the 458 * unit square as well, but in a different coordinate system. 459 * 460 * When viewed in the texture coordinate systems the parallelograms 461 * we are filling are unit squares, but the pixels have then become 462 * tiny parallelograms themselves. Both of the texture coordinate 463 * systems are affine transforms so the rate of change in X and Y 464 * of the texture coordinates are essentially constants and happen 465 * to correspond to the size and direction of the slanted sides of 466 * the distorted pixels relative to the "square mapped" boundary 467 * of the parallelograms. 468 * 469 * The shader uses the dFdx() and dFdy() functions to measure the "rate 470 * of change" of these texture coordinates and thus gets an accurate 471 * measure of the size and shape of a pixel relative to the two 472 * parallelograms. It then uses the bounds of the size and shape 473 * of a pixel to intersect with the unit square to estimate the 474 * coverage of the pixel. Unfortunately, without a lot more work 475 * to calculate the exact area of intersection between a unit 476 * square (the original parallelogram) and a parallelogram (the 477 * distorted pixel), this shader only approximates the pixel 478 * coverage, but emperically the estimate is very useful and 479 * produces visually pleasing results, if not theoretically accurate. 480 */ 481 static const char *aaPgramShaderSource = 482 "void main() {" 483 // Calculate the vectors for the "legs" of the pixel parallelogram 484 // for the outer parallelogram. 485 " vec2 oleg1 = dFdx(gl_TexCoord[0].st);" 486 " vec2 oleg2 = dFdy(gl_TexCoord[0].st);" 487 // Calculate the bounds of the distorted pixel parallelogram. 488 " vec2 corner = gl_TexCoord[0].st - (oleg1+oleg2)/2.0;" 489 " vec2 omin = min(corner, corner+oleg1);" 490 " omin = min(omin, corner+oleg2);" 491 " omin = min(omin, corner+oleg1+oleg2);" 492 " vec2 omax = max(corner, corner+oleg1);" 493 " omax = max(omax, corner+oleg2);" 494 " omax = max(omax, corner+oleg1+oleg2);" 495 // Calculate the vectors for the "legs" of the pixel parallelogram 496 // for the inner parallelogram. 497 " vec2 ileg1 = dFdx(gl_TexCoord[1].st);" 498 " vec2 ileg2 = dFdy(gl_TexCoord[1].st);" 499 // Calculate the bounds of the distorted pixel parallelogram. 500 " corner = gl_TexCoord[1].st - (ileg1+ileg2)/2.0;" 501 " vec2 imin = min(corner, corner+ileg1);" 502 " imin = min(imin, corner+ileg2);" 503 " imin = min(imin, corner+ileg1+ileg2);" 504 " vec2 imax = max(corner, corner+ileg1);" 505 " imax = max(imax, corner+ileg2);" 506 " imax = max(imax, corner+ileg1+ileg2);" 507 // Clamp the bounds of the parallelograms to the unit square to 508 // estimate the intersection of the pixel parallelogram with 509 // the unit square. The ratio of the 2 rectangle areas is a 510 // reasonable estimate of the proportion of coverage. 511 " vec2 o1 = clamp(omin, 0.0, 1.0);" 512 " vec2 o2 = clamp(omax, 0.0, 1.0);" 513 " float oint = (o2.y-o1.y)*(o2.x-o1.x);" 514 " float oarea = (omax.y-omin.y)*(omax.x-omin.x);" 515 " vec2 i1 = clamp(imin, 0.0, 1.0);" 516 " vec2 i2 = clamp(imax, 0.0, 1.0);" 517 " float iint = (i2.y-i1.y)*(i2.x-i1.x);" 518 " float iarea = (imax.y-imin.y)*(imax.x-imin.x);" 519 // Proportion of pixel in outer shape minus the proportion 520 // of pixel in the inner shape == the coverage of the pixel 521 // in the area between the two. 522 " float coverage = oint/oarea - iint / iarea;" 523 " gl_FragColor = gl_Color * coverage;" 524 "}"; 525 526 #define ADJUST_PGRAM(V1, DV, V2) \ 527 do { \ 528 if ((DV) >= 0) { \ 529 (V2) += (DV); \ 530 } else { \ 531 (V1) += (DV); \ 532 } \ 533 } while (0) 534 535 // Invert the following transform: 536 // DeltaT(0, 0) == (0, 0) 537 // DeltaT(1, 0) == (DX1, DY1) 538 // DeltaT(0, 1) == (DX2, DY2) 539 // DeltaT(1, 1) == (DX1+DX2, DY1+DY2) 540 // TM00 = DX1, TM01 = DX2, (TM02 = X11) 541 // TM10 = DY1, TM11 = DY2, (TM12 = Y11) 542 // Determinant = TM00*TM11 - TM01*TM10 543 // = DX1*DY2 - DX2*DY1 544 // Inverse is: 545 // IM00 = TM11/det, IM01 = -TM01/det 546 // IM10 = -TM10/det, IM11 = TM00/det 547 // IM02 = (TM01 * TM12 - TM11 * TM02) / det, 548 // IM12 = (TM10 * TM02 - TM00 * TM12) / det, 549 550 #define DECLARE_MATRIX(MAT) \ 551 jfloat MAT ## 00, MAT ## 01, MAT ## 02, MAT ## 10, MAT ## 11, MAT ## 12 552 553 #define GET_INVERTED_MATRIX(MAT, X11, Y11, DX1, DY1, DX2, DY2, RET_CODE) \ 554 do { \ 555 jfloat det = DX1*DY2 - DX2*DY1; \ 556 if (det == 0) { \ 557 RET_CODE; \ 558 } \ 559 MAT ## 00 = DY2/det; \ 560 MAT ## 01 = -DX2/det; \ 561 MAT ## 10 = -DY1/det; \ 562 MAT ## 11 = DX1/det; \ 563 MAT ## 02 = (DX2 * Y11 - DY2 * X11) / det; \ 564 MAT ## 12 = (DY1 * X11 - DX1 * Y11) / det; \ 565 } while (0) 566 567 #define TRANSFORM(MAT, TX, TY, X, Y) \ 568 do { \ 569 TX = (X) * MAT ## 00 + (Y) * MAT ## 01 + MAT ## 02; \ 570 TY = (X) * MAT ## 10 + (Y) * MAT ## 11 + MAT ## 12; \ 571 } while (0) 572 573 void 574 MTLRenderer_FillAAParallelogram(MTLContext *mtlc, BMTLSDOps *dstOps, 575 jfloat fx11, jfloat fy11, 576 jfloat dx21, jfloat dy21, 577 jfloat dx12, jfloat dy12) 578 { 579 //TODO 580 J2dTraceNotImplPrimitive("MTLRenderer_FillAAParallelogram"); 581 DECLARE_MATRIX(om); 582 // parameters for parallelogram bounding box 583 jfloat bx11, by11, bx22, by22; 584 // parameters for uv texture coordinates of parallelogram corners 585 jfloat u11, v11, u12, v12, u21, v21, u22, v22; 586 587 J2dTraceLn6(J2D_TRACE_INFO, 588 "MTLRenderer_FillAAParallelogram " 589 "(x=%6.2f y=%6.2f " 590 "dx1=%6.2f dy1=%6.2f " 591 "dx2=%6.2f dy2=%6.2f)", 592 fx11, fy11, 593 dx21, dy21, 594 dx12, dy12); 595 596 } 597 598 void 599 MTLRenderer_FillAAParallelogramInnerOuter(MTLContext *mtlc, MTLSDOps *dstOps, 600 jfloat ox11, jfloat oy11, 601 jfloat ox21, jfloat oy21, 602 jfloat ox12, jfloat oy12, 603 jfloat ix11, jfloat iy11, 604 jfloat ix21, jfloat iy21, 605 jfloat ix12, jfloat iy12) 606 { 607 //TODO 608 J2dTraceNotImplPrimitive("MTLRenderer_FillAAParallelogramInnerOuter"); 609 } 610 611 void 612 MTLRenderer_DrawAAParallelogram(MTLContext *mtlc, BMTLSDOps *dstOps, 613 jfloat fx11, jfloat fy11, 614 jfloat dx21, jfloat dy21, 615 jfloat dx12, jfloat dy12, 616 jfloat lwr21, jfloat lwr12) 617 { 618 //TODO 619 J2dTraceNotImplPrimitive("MTLRenderer_DrawAAParallelogram"); 620 // dx,dy for line width in the "21" and "12" directions. 621 jfloat ldx21, ldy21, ldx12, ldy12; 622 // parameters for "outer" parallelogram 623 jfloat ofx11, ofy11, odx21, ody21, odx12, ody12; 624 // parameters for "inner" parallelogram 625 jfloat ifx11, ify11, idx21, idy21, idx12, idy12; 626 627 J2dTraceLn8(J2D_TRACE_INFO, 628 "MTLRenderer_DrawAAParallelogram " 629 "(x=%6.2f y=%6.2f " 630 "dx1=%6.2f dy1=%6.2f lwr1=%6.2f " 631 "dx2=%6.2f dy2=%6.2f lwr2=%6.2f)", 632 fx11, fy11, 633 dx21, dy21, lwr21, 634 dx12, dy12, lwr12); 635 636 } 637 638 void 639 MTLRenderer_EnableAAParallelogramProgram() 640 { 641 //TODO 642 J2dTraceNotImplPrimitive("MTLRenderer_EnableAAParallelogramProgram"); 643 J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_EnableAAParallelogramProgram"); 644 } 645 646 void 647 MTLRenderer_DisableAAParallelogramProgram() 648 { 649 //TODO 650 J2dTraceNotImplPrimitive("MTLRenderer_DisableAAParallelogramProgram"); 651 J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_DisableAAParallelogramProgram"); 652 } 653 654 #endif /* !HEADLESS */