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