1 /* 2 * Copyright (c) 2011, 2013, 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 package com.sun.prism.sw; 27 28 import com.sun.glass.ui.Screen; 29 import com.sun.javafx.font.FontResource; 30 import com.sun.javafx.font.FontStrike; 31 import com.sun.javafx.font.Glyph; 32 import com.sun.javafx.font.Metrics; 33 import com.sun.javafx.font.PrismFontFactory; 34 import com.sun.javafx.geom.Ellipse2D; 35 import com.sun.javafx.geom.Line2D; 36 import com.sun.javafx.geom.Point2D; 37 import com.sun.javafx.geom.RectBounds; 38 import com.sun.javafx.geom.Rectangle; 39 import com.sun.javafx.geom.RoundRectangle2D; 40 import com.sun.javafx.geom.Shape; 41 import com.sun.javafx.geom.transform.Affine2D; 42 import com.sun.javafx.geom.transform.BaseTransform; 43 import com.sun.javafx.geom.transform.NoninvertibleTransformException; 44 import com.sun.javafx.scene.text.GlyphList; 45 import com.sun.javafx.sg.prism.NGCamera; 46 import com.sun.javafx.sg.prism.NGLightBase; 47 import com.sun.javafx.sg.prism.NodePath; 48 import com.sun.pisces.GradientColorMap; 49 import com.sun.pisces.PiscesRenderer; 50 import com.sun.pisces.RendererBase; 51 import com.sun.pisces.Transform6; 52 import com.sun.prism.BasicStroke; 53 import com.sun.prism.CompositeMode; 54 import com.sun.prism.PixelFormat; 55 import com.sun.prism.RTTexture; 56 import com.sun.prism.ReadbackGraphics; 57 import com.sun.prism.RenderTarget; 58 import com.sun.prism.Texture; 59 import com.sun.prism.impl.PrismSettings; 60 import com.sun.prism.paint.Color; 61 import com.sun.prism.paint.ImagePattern; 62 import com.sun.prism.paint.Paint; 63 64 final class SWGraphics implements ReadbackGraphics { 65 66 private final PiscesRenderer pr; 67 private final SWContext context; 68 private final SWRTTexture target; 69 private final SWPaint swPaint; 70 71 private final BaseTransform tx = new Affine2D(); 72 73 private CompositeMode compositeMode = CompositeMode.SRC_OVER; 74 75 private Rectangle clip; 76 private final Rectangle finalClip = new Rectangle(); 77 private RectBounds nodeBounds; 78 79 private int clipRectIndex; 80 81 private Paint paint; 82 private BasicStroke stroke; 83 84 private Ellipse2D ellipse2d; 85 private Line2D line2d; 86 private RoundRectangle2D rect2d; 87 88 private boolean hasPreCullingBits = false; 89 90 private NodePath renderRoot; 91 @Override 92 public void setRenderRoot(NodePath root) { 93 this.renderRoot = root; 94 } 95 96 @Override 97 public NodePath getRenderRoot() { 98 return renderRoot; 99 } 100 101 public SWGraphics(SWRTTexture target, SWContext context, PiscesRenderer pr) { 102 this.target = target; 103 this.context = context; 104 this.pr = pr; 105 this.swPaint = new SWPaint(context, pr); 106 107 this.setClipRect(null); 108 } 109 110 public RenderTarget getRenderTarget() { 111 return target; 112 } 113 114 public SWResourceFactory getResourceFactory() { 115 return target.getResourceFactory(); 116 } 117 118 public Screen getAssociatedScreen() { 119 return target.getAssociatedScreen(); 120 } 121 122 public void sync() { 123 } 124 125 public BaseTransform getTransformNoClone() { 126 if (PrismSettings.debug) { 127 System.out.println("+ getTransformNoClone " + this + "; tr: " + tx); 128 } 129 return tx; 130 } 131 132 public void setTransform(BaseTransform xform) { 133 if (xform == null) { 134 xform = BaseTransform.IDENTITY_TRANSFORM; 135 } 136 if (PrismSettings.debug) { 137 System.out.println("+ setTransform " + this + "; tr: " + xform); 138 } 139 tx.setTransform(xform); 140 } 141 142 public void setTransform(double m00, double m10, 143 double m01, double m11, 144 double m02, double m12) { 145 tx.restoreTransform(m00, m10, m01, m11, m02, m12); 146 if (PrismSettings.debug) { 147 System.out.println("+ restoreTransform " + this + "; tr: " + tx); 148 } 149 } 150 151 public void setTransform3D(double mxx, double mxy, double mxz, double mxt, 152 double myx, double myy, double myz, double myt, 153 double mzx, double mzy, double mzz, double mzt) { 154 if (mxz != 0.0 || myz != 0.0 || 155 mzx != 0.0 || mzy != 0.0 || mzz != 1.0 || mzt != 0.0) 156 { 157 throw new UnsupportedOperationException("3D transforms not supported."); 158 } 159 setTransform(mxx, myx, mxy, myy, mxt, myt); 160 } 161 162 public void transform(BaseTransform xform) { 163 if (PrismSettings.debug) { 164 System.out.println("+ concatTransform " + this + "; tr: " + xform); 165 } 166 tx.deriveWithConcatenation(xform); 167 } 168 169 public void translate(float tx, float ty) { 170 if (PrismSettings.debug) { 171 System.out.println("+ concat translate " + this + "; tx: " + tx + "; ty: " + ty); 172 } 173 this.tx.deriveWithTranslation(tx, ty); 174 } 175 176 public void translate(float tx, float ty, float tz) { 177 throw new UnsupportedOperationException("translate3D: unimp"); 178 } 179 180 public void scale(float sx, float sy) { 181 if (PrismSettings.debug) { 182 System.out.println("+ concat scale " + this + "; sx: " + sx + "; sy: " + sy); 183 } 184 tx.deriveWithConcatenation(sx, 0, 0, sy, 0, 0); 185 } 186 187 public void scale(float sx, float sy, float sz) { 188 throw new UnsupportedOperationException("scale3D: unimp"); 189 } 190 191 public void setCamera(NGCamera camera) { 192 } 193 194 public NGCamera getCameraNoClone() { 195 throw new UnsupportedOperationException("getCameraNoClone: unimp"); 196 } 197 198 public void setDepthTest(boolean depthTest) { } 199 200 public boolean isDepthTest() { 201 return false; 202 } 203 204 public void setDepthBuffer(boolean depthBuffer) { } 205 206 public boolean isDepthBuffer() { 207 return false; 208 } 209 210 public Rectangle getClipRect() { 211 return (clip == null) ? null : new Rectangle(clip); 212 } 213 214 public Rectangle getClipRectNoClone() { 215 return clip; 216 } 217 218 public RectBounds getFinalClipNoClone() { 219 return finalClip.toRectBounds(); 220 } 221 222 public void setClipRect(Rectangle clipRect) { 223 finalClip.setBounds(target.getDimensions()); 224 if (clipRect == null) { 225 if (PrismSettings.debug) { 226 System.out.println("+ PR.resetClip"); 227 } 228 clip = null; 229 } else { 230 if (PrismSettings.debug) { 231 System.out.println("+ PR.setClip: " + clipRect); 232 } 233 finalClip.intersectWith(clipRect); 234 clip = new Rectangle(clipRect); 235 } 236 pr.setClip(finalClip.x, finalClip.y, finalClip.width, finalClip.height); 237 } 238 239 public void setHasPreCullingBits(boolean hasBits) { 240 this.hasPreCullingBits = hasBits; 241 } 242 243 public boolean hasPreCullingBits() { 244 return this.hasPreCullingBits; 245 } 246 247 public int getClipRectIndex() { 248 return clipRectIndex; 249 } 250 251 public void setClipRectIndex(int index) { 252 if (PrismSettings.debug) { 253 System.out.println("+ PR.setClipRectIndex: " + index); 254 } 255 clipRectIndex = index; 256 } 257 258 public float getExtraAlpha() { 259 return swPaint.getCompositeAlpha(); 260 } 261 262 public void setExtraAlpha(float extraAlpha) { 263 if (PrismSettings.debug) { 264 System.out.println("PR.setCompositeAlpha, value: " + extraAlpha); 265 } 266 swPaint.setCompositeAlpha(extraAlpha); 267 } 268 269 public Paint getPaint() { 270 return paint; 271 } 272 273 public void setPaint(Paint paint) { 274 this.paint = paint; 275 } 276 277 278 279 public BasicStroke getStroke() { 280 return stroke; 281 } 282 283 public void setStroke(BasicStroke stroke) { 284 this.stroke = stroke; 285 } 286 287 public CompositeMode getCompositeMode() { 288 return compositeMode; 289 } 290 291 public void setCompositeMode(CompositeMode mode) { 292 this.compositeMode = mode; 293 294 int piscesComp; 295 switch (mode) { 296 case CLEAR: 297 piscesComp = RendererBase.COMPOSITE_CLEAR; 298 if (PrismSettings.debug) { 299 System.out.println("PR.setCompositeRule - CLEAR"); 300 } 301 break; 302 case SRC: 303 piscesComp = RendererBase.COMPOSITE_SRC; 304 if (PrismSettings.debug) { 305 System.out.println("PR.setCompositeRule - SRC"); 306 } 307 break; 308 case SRC_OVER: 309 piscesComp = RendererBase.COMPOSITE_SRC_OVER; 310 if (PrismSettings.debug) { 311 System.out.println("PR.setCompositeRule - SRC_OVER"); 312 } 313 break; 314 default: 315 throw new InternalError("Unrecognized composite mode: "+mode); 316 } 317 this.pr.setCompositeRule(piscesComp); 318 } 319 320 public void setNodeBounds(RectBounds bounds) { 321 if (PrismSettings.debug) { 322 System.out.println("+ SWG.setNodeBounds: " + bounds); 323 } 324 nodeBounds = bounds; 325 } 326 327 public void clear() { 328 this.clear(Color.TRANSPARENT); 329 } 330 331 /** 332 * Clears the current {@code RenderTarget} with the given {@code Color}. 333 * Note that this operation is affected by the current clip rectangle, 334 * if set. To clear the entire surface, call {@code setClipRect(null)} 335 * prior to calling {@code clear()}. 336 */ 337 public void clear(Color color) { 338 if (PrismSettings.debug) { 339 System.out.println("+ PR.clear: " + color); 340 } 341 this.swPaint.setColor(color, 1f); 342 pr.clearRect(0, 0, target.getPhysicalWidth(), target.getPhysicalHeight()); 343 getRenderTarget().setOpaque(color.isOpaque()); 344 } 345 346 /** 347 * Clears the region represented by the given quad with transparent pixels. 348 * Note that this operation is affected by the current clip rectangle, 349 * if set, as well as the current transform (the quad is specified in 350 * user space). Also note that unlike the {@code clear()} methods, this 351 * method does not attempt to clear the depth buffer. 352 */ 353 public void clearQuad(float x1, float y1, float x2, float y2) { 354 final CompositeMode cm = this.compositeMode; 355 final Paint p = this.paint; 356 this.setCompositeMode(CompositeMode.SRC); 357 this.setPaint(Color.TRANSPARENT); 358 this.fillQuad(x1, y1, x2, y2); 359 this.setCompositeMode(cm); 360 this.setPaint(p); 361 } 362 363 public void fill(Shape shape) { 364 if (PrismSettings.debug) { 365 System.out.println("+ fill(Shape)"); 366 } 367 paintShape(shape, null, this.tx); 368 } 369 370 public void fillQuad(float x1, float y1, float x2, float y2) { 371 if (PrismSettings.debug) { 372 System.out.println("+ SWG.fillQuad"); 373 } 374 this.fillRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x2 - x1), Math.abs(y2 - y1)); 375 } 376 377 public void fillRect(float x, float y, float width, float height) { 378 if (PrismSettings.debug) { 379 System.out.printf("+ SWG.fillRect, x: %f, y: %f, w: %f, h: %f\n", x, y, width, height); 380 } 381 if (tx.getMxy() == 0 && tx.getMyx() == 0) { 382 if (PrismSettings.debug) { 383 System.out.println("GR: " + this); 384 System.out.println("target: " + target + " t.w: " + target.getPhysicalWidth() + ", t.h: " + target.getPhysicalHeight() + 385 ", t.dims: " + target.getDimensions()); 386 System.out.println("Tx: " + tx); 387 System.out.println("Clip: " + finalClip); 388 System.out.println("Composite rule: " + compositeMode); 389 } 390 391 final Point2D p1 = new Point2D(x, y); 392 final Point2D p2 = new Point2D(x + width, y + height); 393 tx.transform(p1, p1); 394 tx.transform(p2, p2); 395 396 if (this.paint.getType() == Paint.Type.IMAGE_PATTERN) { 397 // we can call pr.drawImage(...) directly 398 final ImagePattern ip = (ImagePattern)this.paint; 399 if (ip.getImage().getPixelFormat() == PixelFormat.BYTE_ALPHA) { 400 throw new UnsupportedOperationException("Alpha image is not supported as an image pattern."); 401 } else { 402 final Transform6 piscesTx = swPaint.computeSetTexturePaintTransform(this.paint, this.tx, this.nodeBounds, x, y, width, height); 403 final SWArgbPreTexture tex = context.validateImagePaintTexture(ip.getImage().getWidth(), ip.getImage().getHeight()); 404 tex.update(ip.getImage()); 405 406 final float compositeAlpha = swPaint.getCompositeAlpha(); 407 final int imageMode; 408 if (compositeAlpha == 1f) { 409 imageMode = RendererBase.IMAGE_MODE_NORMAL; 410 } else { 411 imageMode = RendererBase.IMAGE_MODE_MULTIPLY; 412 this.pr.setColor(255, 255, 255, (int)(255 * compositeAlpha)); 413 } 414 415 this.pr.drawImage(RendererBase.TYPE_INT_ARGB_PRE, imageMode, 416 tex.getDataNoClone(), tex.getContentWidth(), tex.getContentHeight(), 417 tex.getOffset(), tex.getPhysicalWidth(), 418 piscesTx, 419 tex.getWrapMode() == Texture.WrapMode.REPEAT, 420 (int)(Math.min(p1.x, p2.x) * SWUtils.TO_PISCES), (int)(Math.min(p1.y, p2.y) * SWUtils.TO_PISCES), 421 (int)(Math.abs(p2.x - p1.x) * SWUtils.TO_PISCES), (int)(Math.abs(p2.y - p1.y) * SWUtils.TO_PISCES), 422 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP, 423 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP, 424 0, 0, tex.getContentWidth()-1, tex.getContentHeight()-1, 425 tex.hasAlpha()); 426 } 427 } else { 428 swPaint.setPaintFromShape(this.paint, this.tx, null, this.nodeBounds, x, y, width, height); 429 this.pr.fillRect((int)(Math.min(p1.x, p2.x) * SWUtils.TO_PISCES), (int)(Math.min(p1.y, p2.y) * SWUtils.TO_PISCES), 430 (int)(Math.abs(p2.x - p1.x) * SWUtils.TO_PISCES), (int)(Math.abs(p2.y - p1.y) * SWUtils.TO_PISCES)); 431 } 432 } else { 433 this.fillRoundRect(x, y, width, height, 0, 0); 434 } 435 } 436 437 public void fillRoundRect(float x, float y, float width, float height, 438 float arcw, float arch) { 439 if (PrismSettings.debug) { 440 System.out.println("+ SWG.fillRoundRect"); 441 } 442 this.paintRoundRect(x, y, width, height, arcw, arch, null); 443 } 444 445 public void fillEllipse(float x, float y, float width, float height) { 446 if (PrismSettings.debug) { 447 System.out.println("+ SWG.fillEllipse"); 448 } 449 this.paintEllipse(x, y, width, height, null); 450 } 451 452 public void draw(Shape shape) { 453 if (PrismSettings.debug) { 454 System.out.println("+ draw(Shape)"); 455 } 456 paintShape(shape, this.stroke, this.tx); 457 } 458 459 private void paintShape(Shape shape, BasicStroke st, BaseTransform tr) { 460 if (this.finalClip.isEmpty()) { 461 if (PrismSettings.debug) { 462 System.out.println("Final clip is empty: not rendering the shape: " + shape); 463 } 464 return; 465 } 466 swPaint.setPaintFromShape(this.paint, this.tx, shape, this.nodeBounds, 0,0,0,0); 467 this.paintShapePaintAlreadySet(shape, st, tr); 468 } 469 470 private void paintShapePaintAlreadySet(Shape shape, BasicStroke st, BaseTransform tr) { 471 if (this.finalClip.isEmpty()) { 472 if (PrismSettings.debug) { 473 System.out.println("Final clip is empty: not rendering the shape: " + shape); 474 } 475 return; 476 } 477 478 if (PrismSettings.debug) { 479 System.out.println("GR: " + this); 480 System.out.println("target: " + target + " t.w: " + target.getPhysicalWidth() + ", t.h: " + target.getPhysicalHeight() + 481 ", t.dims: " + target.getDimensions()); 482 System.out.println("Shape: " + shape); 483 System.out.println("Stroke: " + st); 484 System.out.println("Tx: " + tr); 485 System.out.println("Clip: " + finalClip); 486 System.out.println("Composite rule: " + compositeMode); 487 } 488 context.renderShape(this.pr, shape, st, tr, this.finalClip); 489 } 490 491 private void paintRoundRect(float x, float y, float width, float height, float arcw, float arch, BasicStroke st) { 492 if (rect2d == null) { 493 rect2d = new RoundRectangle2D(x, y, width, height, arcw, arch); 494 } else { 495 rect2d.setRoundRect(x, y, width, height, arcw, arch); 496 } 497 paintShape(this.rect2d, st, this.tx); 498 } 499 500 private void paintEllipse(float x, float y, float width, float height, BasicStroke st) { 501 if (ellipse2d == null) { 502 ellipse2d = new Ellipse2D(x, y, width, height); 503 } else { 504 ellipse2d.setFrame(x, y, width, height); 505 } 506 paintShape(this.ellipse2d, st, this.tx); 507 } 508 509 public void drawLine(float x1, float y1, float x2, float y2) { 510 if (PrismSettings.debug) { 511 System.out.println("+ drawLine"); 512 } 513 if (line2d == null) { 514 line2d = new Line2D(x1, y1, x2, y2); 515 } else { 516 line2d.setLine(x1, y1, x2, y2); 517 } 518 paintShape(this.line2d, this.stroke, this.tx); 519 } 520 521 public void drawRect(float x, float y, float width, float height) { 522 if (PrismSettings.debug) { 523 System.out.println("+ SWG.drawRect"); 524 } 525 this.drawRoundRect(x, y, width, height, 0, 0); 526 } 527 528 public void drawRoundRect(float x, float y, float width, float height, 529 float arcw, float arch) { 530 if (PrismSettings.debug) { 531 System.out.println("+ SWG.drawRoundRect"); 532 } 533 this.paintRoundRect(x, y, width, height, arcw, arch, stroke); 534 } 535 536 public void drawEllipse(float x, float y, float width, float height) { 537 if (PrismSettings.debug) { 538 System.out.println("+ SWG.drawEllipse"); 539 } 540 this.paintEllipse(x, y, width, height, stroke); 541 } 542 543 public void drawString(GlyphList gl, FontStrike strike, float x, float y, 544 Color selectColor, int selectStart, int selectEnd) { 545 546 if (PrismSettings.debug) { 547 System.out.println("+ SWG.drawGlyphList, gl.Count: " + gl.getGlyphCount() + 548 ", x: " + x + ", y: " + y + 549 ", selectStart: " + selectStart + ", selectEnd: " + selectEnd); 550 } 551 552 final float bx, by, bw, bh; 553 if (paint.isProportional()) { 554 if (nodeBounds != null) { 555 bx = nodeBounds.getMinX(); 556 by = nodeBounds.getMinY(); 557 bw = nodeBounds.getWidth(); 558 bh = nodeBounds.getHeight(); 559 } else { 560 Metrics m = strike.getMetrics(); 561 bx = 0; 562 by = m.getAscent(); 563 bw = gl.getWidth(); 564 bh = m.getLineHeight(); 565 } 566 } else { 567 bx = by = bw = bh = 0; 568 } 569 570 final boolean drawAsMasks = tx.isTranslateOrIdentity() && (!strike.drawAsShapes()); 571 final boolean doLCDText = drawAsMasks && 572 (strike.getAAMode() == FontResource.AA_LCD) && 573 getRenderTarget().isOpaque() && 574 (this.paint.getType() == Paint.Type.COLOR) && 575 tx.is2D(); 576 BaseTransform glyphTx = null; 577 578 if (doLCDText) { 579 this.pr.setLCDGammaCorrection(1f / PrismFontFactory.getLCDContrast()); 580 } else if (drawAsMasks) { 581 final FontResource fr = strike.getFontResource(); 582 final float origSize = strike.getSize(); 583 final BaseTransform origTx = strike.getTransform(); 584 strike = fr.getStrike(origSize, origTx, FontResource.AA_GREYSCALE); 585 } else { 586 glyphTx = new Affine2D(); 587 } 588 589 if (selectColor == null) { 590 swPaint.setPaintBeforeDraw(this.paint, this.tx, bx, by, bw, bh); 591 for (int i = 0; i < gl.getGlyphCount(); i++) { 592 this.drawGlyph(strike, gl, i, glyphTx, drawAsMasks, x, y); 593 } 594 } else { 595 for (int i = 0; i < gl.getGlyphCount(); i++) { 596 final int offset = gl.getCharOffset(i); 597 final boolean selected = selectStart <= offset && offset < selectEnd; 598 swPaint.setPaintBeforeDraw(selected ? selectColor : this.paint, this.tx, bx, by, bw, bh); 599 this.drawGlyph(strike, gl, i, glyphTx, drawAsMasks, x, y); 600 } 601 } 602 } 603 604 private void drawGlyph(FontStrike strike, GlyphList gl, int idx, BaseTransform glyphTx, 605 boolean drawAsMasks, float x, float y) 606 { 607 608 final Glyph g = strike.getGlyph(gl.getGlyphCode(idx)); 609 if (drawAsMasks) { 610 final Point2D pt = new Point2D((float)(x + tx.getMxt() + gl.getPosX(idx)), 611 (float)(y + tx.getMyt() + gl.getPosY(idx))); 612 int subPixel = strike.getQuantizedPosition(pt); 613 final byte pixelData[] = g.getPixelData(subPixel); 614 if (pixelData != null) { 615 final int intPosX = g.getOriginX() + (int)pt.x; 616 final int intPosY = g.getOriginY() + (int)pt.y; 617 if (g.isLCDGlyph()) { 618 this.pr.fillLCDAlphaMask(pixelData, intPosX, intPosY, 619 g.getWidth(), g.getHeight(), 620 0, g.getWidth()); 621 } else { 622 this.pr.fillAlphaMask(pixelData, intPosX, intPosY, 623 g.getWidth(), g.getHeight(), 624 0, g.getWidth()); 625 } 626 } 627 } else { 628 Shape shape = g.getShape(); 629 if (shape != null) { 630 glyphTx.setTransform(tx); 631 glyphTx.deriveWithTranslation(x + gl.getPosX(idx), y + gl.getPosY(idx)); 632 this.paintShapePaintAlreadySet(shape, null, glyphTx); 633 } 634 } 635 } 636 637 public void drawTexture(Texture tex, float x, float y, float w, float h) { 638 if (PrismSettings.debug) { 639 System.out.printf("+ drawTexture1, x: %f, y: %f, w: %f, h: %f\n", x, y, w, h); 640 } 641 this.drawTexture(tex, x, y, x + w, y + h, 0, 0, w, h); 642 } 643 644 public void drawTexture(Texture tex, 645 float dx1, float dy1, float dx2, float dy2, 646 float sx1, float sy1, float sx2, float sy2) 647 { 648 this.drawTexture(tex, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, 649 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP, 650 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP); 651 } 652 653 private void drawTexture(Texture tex, 654 float dx1, float dy1, float dx2, float dy2, 655 float sx1, float sy1, float sx2, float sy2, 656 int lEdge, int rEdge, int tEdge, int bEdge) { 657 final int imageMode; 658 final float compositeAlpha = swPaint.getCompositeAlpha(); 659 if (compositeAlpha == 1f) { 660 imageMode = RendererBase.IMAGE_MODE_NORMAL; 661 } else { 662 imageMode = RendererBase.IMAGE_MODE_MULTIPLY; 663 this.pr.setColor(255, 255, 255, (int)(255 * compositeAlpha)); 664 } 665 this.drawTexture(tex, imageMode, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, lEdge, rEdge, tEdge, bEdge); 666 } 667 668 private void drawTexture(Texture tex, int imageMode, 669 float dx1, float dy1, float dx2, float dy2, 670 float sx1, float sy1, float sx2, float sy2, 671 int lEdge, int rEdge, int tEdge, int bEdge) { 672 if (PrismSettings.debug) { 673 System.out.println("+ drawTexture: " + tex + ", imageMode: " + imageMode + 674 ", tex.w: " + tex.getPhysicalWidth() + ", tex.h: " + tex.getPhysicalHeight() + 675 ", tex.cw: " + tex.getContentWidth() + ", tex.ch: " + tex.getContentHeight()); 676 System.out.println("target: " + target + " t.w: " + target.getPhysicalWidth() + ", t.h: " + target.getPhysicalHeight() + 677 ", t.dims: " + target.getDimensions()); 678 System.out.println("GR: " + this); 679 System.out.println("dx1:" + dx1 + " dy1:" + dy1 + " dx2:" + dx2 + " dy2:" + dy2); 680 System.out.println("sx1:" + sx1 + " sy1:" + sy1 + " sx2:" + sx2 + " sy2:" + sy2); 681 System.out.println("Clip: " + finalClip); 682 System.out.println("Composite rule: " + compositeMode); 683 } 684 685 final SWArgbPreTexture swTex = (SWArgbPreTexture) tex; 686 int data[] = swTex.getDataNoClone(); 687 688 final RectBounds srcBBox = new RectBounds(Math.min(dx1, dx2), Math.min(dy1, dy2), 689 Math.max(dx1, dx2), Math.max(dy1, dy2)); 690 final RectBounds dstBBox = new RectBounds(); 691 tx.transform(srcBBox, dstBBox); 692 693 final Transform6 piscesTx = swPaint.computeDrawTexturePaintTransform(this.tx, 694 dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2); 695 696 if (PrismSettings.debug) { 697 System.out.println("tx: " + tx); 698 System.out.println("piscesTx: " + piscesTx); 699 700 System.out.println("srcBBox: " + srcBBox); 701 System.out.println("dstBBox: " + dstBBox); 702 } 703 704 // texture coordinates range 705 final int txMin = Math.max(0, SWUtils.fastFloor(Math.min(sx1, sx2))); 706 final int tyMin = Math.max(0, SWUtils.fastFloor(Math.min(sy1, sy2))); 707 final int txMax = Math.min(tex.getContentWidth() - 1, SWUtils.fastCeil(Math.max(sx1, sx2)) - 1); 708 final int tyMax = Math.min(tex.getContentHeight() - 1, SWUtils.fastCeil(Math.max(sy1, sy2)) - 1); 709 710 this.pr.drawImage(RendererBase.TYPE_INT_ARGB_PRE, imageMode, 711 data, tex.getContentWidth(), tex.getContentHeight(), 712 swTex.getOffset(), tex.getPhysicalWidth(), 713 piscesTx, 714 tex.getWrapMode() == Texture.WrapMode.REPEAT, 715 (int)(SWUtils.TO_PISCES * dstBBox.getMinX()), (int)(SWUtils.TO_PISCES * dstBBox.getMinY()), 716 (int)(SWUtils.TO_PISCES * dstBBox.getWidth()), (int)(SWUtils.TO_PISCES * dstBBox.getHeight()), 717 lEdge, rEdge, tEdge, bEdge, 718 txMin, tyMin, txMax, tyMax, 719 swTex.hasAlpha()); 720 721 if (PrismSettings.debug) { 722 System.out.println("* drawTexture, DONE"); 723 } 724 } 725 726 @Override 727 public void drawTexture3SliceH(Texture tex, 728 float dx1, float dy1, float dx2, float dy2, 729 float sx1, float sy1, float sx2, float sy2, 730 float dh1, float dh2, float sh1, float sh2) 731 { 732 drawTexture(tex, dx1, dy1, dh1, dy2, sx1, sy1, sh1, sy2, 733 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_PAD, 734 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP); 735 drawTexture(tex, dh1, dy1, dh2, dy2, sh1, sy1, sh2, sy2, 736 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_PAD, 737 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP); 738 drawTexture(tex, dh2, dy1, dx2, dy2, sh2, sy1, sx2, sy2, 739 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_KEEP, 740 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP); 741 } 742 743 @Override 744 public void drawTexture3SliceV(Texture tex, 745 float dx1, float dy1, float dx2, float dy2, 746 float sx1, float sy1, float sx2, float sy2, 747 float dv1, float dv2, float sv1, float sv2) 748 { 749 drawTexture(tex, dx1, dy1, dx2, dv1, sx1, sy1, sx2, sv1, 750 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP, 751 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_PAD); 752 drawTexture(tex, dx1, dv1, dx2, dv2, sx1, sv1, sx2, sv2, 753 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP, 754 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_PAD); 755 drawTexture(tex, dx1, dv2, dx2, dy2, sx1, sv2, sx2, sy2, 756 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP, 757 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_KEEP); 758 } 759 760 @Override 761 public void drawTexture9Slice(Texture tex, 762 float dx1, float dy1, float dx2, float dy2, 763 float sx1, float sy1, float sx2, float sy2, 764 float dh1, float dv1, float dh2, float dv2, 765 float sh1, float sv1, float sh2, float sv2) 766 { 767 drawTexture(tex, dx1, dy1, dh1, dv1, sx1, sy1, sh1, sv1, 768 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_PAD, 769 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_PAD); 770 drawTexture(tex, dh1, dy1, dh2, dv1, sh1, sy1, sh2, sv1, 771 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_PAD, 772 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_PAD); 773 drawTexture(tex, dh2, dy1, dx2, dv1, sh2, sy1, sx2, sv1, 774 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_KEEP, 775 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_PAD); 776 777 drawTexture(tex, dx1, dv1, dh1, dv2, sx1, sv1, sh1, sv2, 778 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_PAD, 779 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_PAD); 780 drawTexture(tex, dh1, dv1, dh2, dv2, sh1, sv1, sh2, sv2, 781 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_PAD, 782 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_PAD); 783 drawTexture(tex, dh2, dv1, dx2, dv2, sh2, sv1, sx2, sv2, 784 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_KEEP, 785 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_PAD); 786 787 drawTexture(tex, dx1, dv2, dh1, dy2, sx1, sv2, sh1, sy2, 788 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_PAD, 789 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_KEEP); 790 drawTexture(tex, dh1, dv2, dh2, dy2, sh1, sv2, sh2, sy2, 791 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_PAD, 792 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_KEEP); 793 drawTexture(tex, dh2, dv2, dx2, dy2, sh2, sv2, sx2, sy2, 794 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_KEEP, 795 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_KEEP); 796 } 797 798 public void drawTextureVO(Texture tex, 799 float topopacity, float botopacity, 800 float dx1, float dy1, float dx2, float dy2, 801 float sx1, float sy1, float sx2, float sy2) 802 { 803 if (PrismSettings.debug) { 804 System.out.println("* drawTextureVO"); 805 } 806 final int[] fractions = { 0x0000, 0x10000 }; 807 final int[] argb = { 0xffffff | (((int)(topopacity * 255)) << 24), 808 0xffffff | (((int)(botopacity * 255)) << 24) }; 809 final Transform6 t6 = new Transform6(); 810 SWUtils.convertToPiscesTransform(this.tx, t6); 811 this.pr.setLinearGradient(0, (int)(SWUtils.TO_PISCES * dy1), 0, (int)(SWUtils.TO_PISCES * dy2), fractions, argb, 812 GradientColorMap.CYCLE_NONE, t6); 813 this.drawTexture(tex, RendererBase.IMAGE_MODE_MULTIPLY, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, 814 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP, 815 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP); 816 } 817 818 public void drawTextureRaw(Texture tex, 819 float dx1, float dy1, float dx2, float dy2, 820 float tx1, float ty1, float tx2, float ty2) 821 { 822 if (PrismSettings.debug) { 823 System.out.println("+ drawTextureRaw"); 824 } 825 826 int w = tex.getContentWidth(); 827 int h = tex.getContentHeight(); 828 tx1 *= w; 829 ty1 *= h; 830 tx2 *= w; 831 ty2 *= h; 832 drawTexture(tex, dx1, dy1, dx2, dy2, tx1, ty1, tx2, ty2); 833 } 834 835 public void drawMappedTextureRaw(Texture tex, 836 float dx1, float dy1, float dx2, float dy2, 837 float tx11, float ty11, float tx21, float ty21, 838 float tx12, float ty12, float tx22, float ty22) 839 { 840 if (PrismSettings.debug) { 841 System.out.println("+ drawMappedTextureRaw"); 842 } 843 844 final double _mxx, _myx, _mxy, _myy, _mxt, _myt; 845 _mxx = tx.getMxx(); 846 _myx = tx.getMyx(); 847 _mxy = tx.getMxy(); 848 _myy = tx.getMyy(); 849 _mxt = tx.getMxt(); 850 _myt = tx.getMyt(); 851 852 try { 853 final float mxx = tx21-tx11; 854 final float myx = ty21-ty11; 855 final float mxy = tx12-tx11; 856 final float myy = ty12-ty11; 857 858 final BaseTransform tmpTx = new Affine2D(mxx, myx, mxy, myy, tx11, ty11); 859 tmpTx.invert(); 860 861 tx.setToIdentity(); 862 tx.deriveWithTranslation(dx1, dy1); 863 tx.deriveWithConcatenation(dx2 - dx1, 0, 0, dy2 - dy2, 0, 0); 864 tx.deriveWithConcatenation(tmpTx); 865 this.drawTexture(tex, 0, 0, 1, 1, 0, 0, tex.getContentWidth(), tex.getContentHeight()); 866 } catch (NoninvertibleTransformException e) { } 867 868 tx.restoreTransform(_mxx, _myx, _mxy, _myy, _mxt, _myt); 869 } 870 871 public boolean canReadBack() { 872 return true; 873 } 874 875 public RTTexture readBack(Rectangle view) { 876 if (PrismSettings.debug) { 877 System.out.println("+ readBack, rect: " + view + ", target.dims: " + target.getDimensions()); 878 } 879 880 final int w = Math.max(1, view.width); 881 final int h = Math.max(1, view.height); 882 final SWRTTexture rbb = context.validateRBBuffer(w, h); 883 884 if (view.isEmpty()) { 885 return rbb; 886 } 887 888 final int pixels[] = rbb.getDataNoClone(); 889 this.target.getSurface().getRGB(pixels, 0, rbb.getPhysicalWidth(), view.x, view.y, w, h); 890 return rbb; 891 } 892 893 public void releaseReadBackBuffer(RTTexture view) { 894 } 895 896 public void setState3D(boolean flag) { 897 } 898 899 public boolean isState3D() { 900 return false; 901 } 902 903 public void setup3DRendering() { 904 } 905 906 @Override 907 public void setLights(NGLightBase[] lights) { 908 // Light are not supported by SW pipeline 909 } 910 911 @Override 912 public NGLightBase[] getLights() { 913 // Light are not supported by SW pipeline 914 return null; 915 } 916 917 @Override 918 public void blit(RTTexture srcTex, RTTexture dstTex, 919 int srcX0, int srcY0, int srcX1, int srcY1, 920 int dstX0, int dstY0, int dstX1, int dstY1) { 921 throw new UnsupportedOperationException("Not supported yet."); 922 } 923 }