1 /* 2 * Copyright (c) 2009, 2015, 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.impl; 27 28 import com.sun.glass.ui.Screen; 29 import com.sun.javafx.geom.Ellipse2D; 30 import com.sun.javafx.geom.Line2D; 31 import com.sun.javafx.geom.RectBounds; 32 import com.sun.javafx.geom.Rectangle; 33 import com.sun.javafx.geom.RoundRectangle2D; 34 import com.sun.javafx.geom.Shape; 35 import com.sun.javafx.geom.transform.Affine3D; 36 import com.sun.javafx.geom.transform.BaseTransform; 37 import com.sun.javafx.sg.prism.NGCamera; 38 import com.sun.javafx.sg.prism.NodePath; 39 import com.sun.prism.BasicStroke; 40 import com.sun.prism.CompositeMode; 41 import com.sun.prism.PixelFormat; 42 import com.sun.prism.RectShadowGraphics; 43 import com.sun.prism.RenderTarget; 44 import com.sun.prism.ResourceFactory; 45 import com.sun.prism.Texture; 46 import com.sun.prism.paint.Color; 47 import com.sun.prism.paint.Paint; 48 49 public abstract class BaseGraphics implements RectShadowGraphics { 50 51 private static final BasicStroke DEFAULT_STROKE = 52 new BasicStroke(1.0f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10.0f); 53 private static final Paint DEFAULT_PAINT = Color.WHITE; 54 55 protected static final RoundRectangle2D scratchRRect = new RoundRectangle2D(); 56 protected static final Ellipse2D scratchEllipse = new Ellipse2D(); 57 protected static final Line2D scratchLine = new Line2D(); 58 protected static final BaseTransform IDENT = BaseTransform.IDENTITY_TRANSFORM; 59 60 // TODO: initialize transform lazily to avoid creating garbage... (RT-27422) 61 private final Affine3D transform3D = new Affine3D(); 62 private NGCamera camera = NGCamera.INSTANCE; 63 private RectBounds devClipRect; 64 private RectBounds finalClipRect; 65 protected RectBounds nodeBounds = null; 66 private Rectangle clipRect; 67 private int clipRectIndex; 68 private boolean hasPreCullingBits = false; 69 private float extraAlpha = 1f; 70 private CompositeMode compMode; 71 private boolean antialiasedShape = true; 72 private boolean depthBuffer = false; 73 private boolean depthTest = false; 74 protected Paint paint = DEFAULT_PAINT; 75 protected BasicStroke stroke = DEFAULT_STROKE; 76 77 protected boolean isSimpleTranslate = true; 78 protected float transX; 79 protected float transY; 80 81 private final BaseContext context; 82 private final RenderTarget renderTarget; 83 private boolean state3D = false; 84 private float pixelScaleX = 1.0f; 85 private float pixelScaleY = 1.0f; 86 87 protected BaseGraphics(BaseContext context, RenderTarget target) { 88 this.context = context; 89 this.renderTarget = target; 90 devClipRect = new RectBounds(0, 0, 91 target.getContentWidth(), 92 target.getContentHeight()); 93 finalClipRect = new RectBounds(devClipRect); 94 compMode = CompositeMode.SRC_OVER; 95 if (context != null) { 96 // RT-27422 97 // TODO: Ideally we wouldn't need this step here and would 98 // instead call some method prior to making any OpenGL calls 99 // to ensure that there is a current context. We're getting 100 // closer to that ideal in that we call validate*Op() before 101 // every graphics operation (which in turn calls the 102 // setRenderTarget() method), but there are still some cases 103 // remaining where this doesn't happen (e.g. texture creation). 104 // So for the time being this blanket call to setRenderTarget() 105 // is better than nothing... 106 context.setRenderTarget(this); 107 } 108 } 109 110 protected NGCamera getCamera() { 111 return camera; 112 } 113 114 public RenderTarget getRenderTarget() { 115 return renderTarget; 116 } 117 118 @Override 119 public void setState3D(boolean flag) { 120 this.state3D = flag; 121 } 122 123 @Override 124 public boolean isState3D() { 125 return state3D; 126 } 127 128 public Screen getAssociatedScreen() { 129 return context.getAssociatedScreen(); 130 } 131 132 public ResourceFactory getResourceFactory() { 133 return context.getResourceFactory(); 134 } 135 136 public BaseTransform getTransformNoClone() { 137 return transform3D; 138 } 139 140 public void setTransform(BaseTransform transform) { 141 if (transform == null) { 142 transform3D.setToIdentity(); 143 } else { 144 transform3D.setTransform(transform); 145 } 146 validateTransformAndPaint(); 147 } 148 149 public void setTransform(double m00, double m10, 150 double m01, double m11, 151 double m02, double m12) 152 { 153 transform3D.setTransform(m00, m10, m01, m11, m02, m12); 154 validateTransformAndPaint(); 155 } 156 157 public void setTransform3D(double mxx, double mxy, double mxz, double mxt, 158 double myx, double myy, double myz, double myt, 159 double mzx, double mzy, double mzz, double mzt) 160 { 161 transform3D.setTransform(mxx, mxy, mxz, mxt, 162 myx, myy, myz, myt, 163 mzx, mzy, mzz, mzt); 164 validateTransformAndPaint(); 165 } 166 167 public void transform(BaseTransform transform) { 168 transform3D.concatenate(transform); 169 validateTransformAndPaint(); 170 } 171 172 public void translate(float tx, float ty) { 173 if (tx != 0f || ty != 0f) { 174 transform3D.translate(tx, ty); 175 validateTransformAndPaint(); 176 } 177 } 178 179 public void translate(float tx, float ty, float tz) { 180 if (tx != 0f || ty != 0f || tz != 0f) { 181 transform3D.translate(tx, ty, tz); 182 validateTransformAndPaint(); 183 } 184 } 185 186 public void scale(float sx, float sy) { 187 if (sx != 1f || sy != 1f) { 188 transform3D.scale(sx, sy); 189 validateTransformAndPaint(); 190 } 191 } 192 193 public void scale(float sx, float sy, float sz) { 194 if (sx != 1f || sy != 1f || sz != 1f) { 195 transform3D.scale(sx, sy, sz); 196 validateTransformAndPaint(); 197 } 198 } 199 200 public void setClipRectIndex(int index) { 201 this.clipRectIndex = index; 202 } 203 public int getClipRectIndex() { 204 return this.clipRectIndex; 205 } 206 207 public void setHasPreCullingBits(boolean hasBits) { 208 this.hasPreCullingBits = hasBits; 209 } 210 211 public boolean hasPreCullingBits() { 212 return hasPreCullingBits; 213 } 214 215 private NodePath renderRoot; 216 @Override 217 public final void setRenderRoot(NodePath root) { 218 this.renderRoot = root; 219 } 220 221 @Override 222 public final NodePath getRenderRoot() { 223 return renderRoot; 224 } 225 226 private void validateTransformAndPaint() { 227 if (transform3D.isTranslateOrIdentity() && 228 paint.getType() == Paint.Type.COLOR) 229 { 230 // RT-27422 231 // TODO: we could probably extend this to include 232 // proportional paints in addition to simple colors... 233 isSimpleTranslate = true; 234 transX = (float)transform3D.getMxt(); 235 transY = (float)transform3D.getMyt(); 236 } else { 237 isSimpleTranslate = false; 238 transX = 0f; 239 transY = 0f; 240 } 241 } 242 243 public NGCamera getCameraNoClone() { 244 return camera; 245 } 246 247 public void setDepthTest(boolean depthTest) { 248 this.depthTest = depthTest; 249 } 250 251 public boolean isDepthTest() { 252 return depthTest; 253 } 254 255 public void setDepthBuffer(boolean depthBuffer) { 256 this.depthBuffer = depthBuffer; 257 } 258 259 public boolean isDepthBuffer() { 260 return depthBuffer; 261 } 262 263 // If true use fragment shader that does alpha testing (i.e. discard if alpha == 0.0) 264 // Currently it is required when depth testing is in use. 265 public boolean isAlphaTestShader() { 266 return (PrismSettings.forceAlphaTestShader || (isDepthTest() && isDepthBuffer())); 267 } 268 269 public void setAntialiasedShape(boolean aa) { 270 antialiasedShape = aa; 271 } 272 273 public boolean isAntialiasedShape() { 274 return antialiasedShape; 275 } 276 277 @Override 278 public void setPixelScaleFactors(float pixelScaleX, float pixelScaleY) { 279 this.pixelScaleX = pixelScaleX; 280 this.pixelScaleY = pixelScaleY; 281 } 282 283 @Override 284 public float getPixelScaleFactorX() { 285 return pixelScaleX; 286 } 287 288 @Override 289 public float getPixelScaleFactorY() { 290 return pixelScaleY; 291 } 292 293 public void setCamera(NGCamera camera) { 294 this.camera = camera; 295 } 296 297 public Rectangle getClipRect() { 298 return (clipRect != null) ? new Rectangle(clipRect) : null; 299 } 300 301 public Rectangle getClipRectNoClone() { 302 return clipRect; 303 } 304 305 public RectBounds getFinalClipNoClone() { 306 return finalClipRect; 307 } 308 309 public void setClipRect(Rectangle clipRect) { 310 this.finalClipRect.setBounds(devClipRect); 311 if (clipRect == null) { 312 this.clipRect = null; 313 } else { 314 this.clipRect = new Rectangle(clipRect); 315 this.finalClipRect.intersectWith(clipRect); 316 } 317 } 318 319 public float getExtraAlpha() { 320 return extraAlpha; 321 } 322 323 public void setExtraAlpha(float extraAlpha) { 324 this.extraAlpha = extraAlpha; 325 } 326 327 public CompositeMode getCompositeMode() { 328 return compMode; 329 } 330 331 public void setCompositeMode(CompositeMode compMode) { 332 this.compMode = compMode; 333 } 334 335 public Paint getPaint() { 336 return paint; 337 } 338 339 public void setPaint(Paint paint) { 340 this.paint = paint; 341 validateTransformAndPaint(); 342 } 343 344 public BasicStroke getStroke() { 345 return stroke; 346 } 347 348 public void setStroke(BasicStroke stroke) { 349 this.stroke = stroke; 350 } 351 352 public void clear() { 353 clear(Color.TRANSPARENT); 354 } 355 356 protected abstract void renderShape(Shape shape, BasicStroke stroke, 357 float bx, float by, float bw, float bh); 358 359 public void fill(Shape shape) { 360 float bx = 0f, by = 0f, bw = 0f, bh = 0f; 361 if (paint.isProportional()) { 362 if (nodeBounds != null) { 363 bx = nodeBounds.getMinX(); 364 by = nodeBounds.getMinY(); 365 bw = nodeBounds.getWidth(); 366 bh = nodeBounds.getHeight(); 367 } else { 368 float[] bbox = { 369 Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, 370 Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, 371 }; 372 Shape.accumulate(bbox, shape, BaseTransform.IDENTITY_TRANSFORM); 373 bx = bbox[0]; 374 by = bbox[1]; 375 bw = bbox[2] - bx; 376 bh = bbox[3] - by; 377 } 378 } 379 renderShape(shape, null, bx, by, bw, bh); 380 } 381 382 public void draw(Shape shape) { 383 float bx = 0f, by = 0f, bw = 0f, bh = 0f; 384 if (paint.isProportional()) { 385 if (nodeBounds != null) { 386 bx = nodeBounds.getMinX(); 387 by = nodeBounds.getMinY(); 388 bw = nodeBounds.getWidth(); 389 bh = nodeBounds.getHeight(); 390 } else { 391 float[] bbox = { 392 Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, 393 Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, 394 }; 395 Shape.accumulate(bbox, shape, BaseTransform.IDENTITY_TRANSFORM); 396 bx = bbox[0]; 397 by = bbox[1]; 398 bw = bbox[2] - bx; 399 bh = bbox[3] - by; 400 } 401 } 402 renderShape(shape, stroke, bx, by, bw, bh); 403 } 404 405 @Override 406 public void drawTexture(Texture tex, float x, float y, float w, float h) { 407 drawTexture(tex, 408 x, y, x+w, y+h, 409 0, 0, w, h); 410 } 411 412 @Override 413 public void drawTexture(Texture tex, 414 float dx1, float dy1, float dx2, float dy2, 415 float sx1, float sy1, float sx2, float sy2) 416 { 417 BaseTransform xform = isSimpleTranslate ? IDENT : getTransformNoClone(); 418 PixelFormat format = tex.getPixelFormat(); 419 if (format == PixelFormat.BYTE_ALPHA) { 420 // Note that we treat this as a paint operation, using the 421 // given texture as the alpha mask; perhaps it would be better 422 // to treat this as a separate operation from drawTexture(), but 423 // overloading drawTexture() seems like an equally valid option. 424 context.validatePaintOp(this, xform, tex, dx1, dy1, dx2-dx1, dy2-dy1); 425 } else { 426 context.validateTextureOp(this, xform, tex, format); 427 } 428 if (isSimpleTranslate) { 429 // The validatePaintOp bounds above needed to use the original 430 // coordinates (prior to any translation below) for relative 431 // paint processing. 432 dx1 += transX; 433 dy1 += transY; 434 dx2 += transX; 435 dy2 += transY; 436 } 437 438 float pw = tex.getPhysicalWidth(); 439 float ph = tex.getPhysicalHeight(); 440 float cx1 = tex.getContentX(); 441 float cy1 = tex.getContentY(); 442 float tx1 = (cx1 + sx1) / pw; 443 float ty1 = (cy1 + sy1) / ph; 444 float tx2 = (cx1 + sx2) / pw; 445 float ty2 = (cy1 + sy2) / ph; 446 447 VertexBuffer vb = context.getVertexBuffer(); 448 if (context.isSuperShaderEnabled()) { 449 vb.addSuperQuad(dx1, dy1, dx2, dy2, tx1, ty1, tx2, ty2, false); 450 } else { 451 vb.addQuad(dx1, dy1, dx2, dy2, tx1, ty1, tx2, ty2); 452 } 453 } 454 455 @Override 456 public void drawTexture3SliceH(Texture tex, 457 float dx1, float dy1, float dx2, float dy2, 458 float sx1, float sy1, float sx2, float sy2, 459 float dh1, float dh2, float sh1, float sh2) 460 { 461 BaseTransform xform = isSimpleTranslate ? IDENT : getTransformNoClone(); 462 PixelFormat format = tex.getPixelFormat(); 463 if (format == PixelFormat.BYTE_ALPHA) { 464 // Note that we treat this as a paint operation, using the 465 // given texture as the alpha mask; perhaps it would be better 466 // to treat this as a separate operation from drawTexture(), but 467 // overloading drawTexture() seems like an equally valid option. 468 context.validatePaintOp(this, xform, tex, dx1, dy1, dx2-dx1, dy2-dy1); 469 } else { 470 context.validateTextureOp(this, xform, tex, format); 471 } 472 if (isSimpleTranslate) { 473 // The validatePaintOp bounds above needed to use the original 474 // coordinates (prior to any translation below) for relative 475 // paint processing. 476 dx1 += transX; 477 dy1 += transY; 478 dx2 += transX; 479 dy2 += transY; 480 dh1 += transX; 481 // dv1 += transY; 482 dh2 += transX; 483 // dv2 += transY; 484 } 485 486 float pw = tex.getPhysicalWidth(); 487 float ph = tex.getPhysicalHeight(); 488 float cx1 = tex.getContentX(); 489 float cy1 = tex.getContentY(); 490 float tx1 = (cx1 + sx1) / pw; 491 float ty1 = (cy1 + sy1) / ph; 492 float tx2 = (cx1 + sx2) / pw; 493 float ty2 = (cy1 + sy2) / ph; 494 float th1 = (cx1 + sh1) / pw; 495 // float tv1 = (cy1 + sv1) / ph; 496 float th2 = (cx1 + sh2) / pw; 497 // float tv2 = (cy1 + sv2) / ph; 498 499 VertexBuffer vb = context.getVertexBuffer(); 500 if (context.isSuperShaderEnabled()) { 501 vb.addSuperQuad(dx1, dy1, dh1, dy2, tx1, ty1, th1, ty2, false); 502 vb.addSuperQuad(dh1, dy1, dh2, dy2, th1, ty1, th2, ty2, false); 503 vb.addSuperQuad(dh2, dy1, dx2, dy2, th2, ty1, tx2, ty2, false); 504 } else { 505 vb.addQuad(dx1, dy1, dh1, dy2, tx1, ty1, th1, ty2); 506 vb.addQuad(dh1, dy1, dh2, dy2, th1, ty1, th2, ty2); 507 vb.addQuad(dh2, dy1, dx2, dy2, th2, ty1, tx2, ty2); 508 } 509 } 510 511 @Override 512 public void drawTexture3SliceV(Texture tex, 513 float dx1, float dy1, float dx2, float dy2, 514 float sx1, float sy1, float sx2, float sy2, 515 float dv1, float dv2, float sv1, float sv2) 516 { 517 BaseTransform xform = isSimpleTranslate ? IDENT : getTransformNoClone(); 518 PixelFormat format = tex.getPixelFormat(); 519 if (format == PixelFormat.BYTE_ALPHA) { 520 // Note that we treat this as a paint operation, using the 521 // given texture as the alpha mask; perhaps it would be better 522 // to treat this as a separate operation from drawTexture(), but 523 // overloading drawTexture() seems like an equally valid option. 524 context.validatePaintOp(this, xform, tex, dx1, dy1, dx2-dx1, dy2-dy1); 525 } else { 526 context.validateTextureOp(this, xform, tex, format); 527 } 528 if (isSimpleTranslate) { 529 // The validatePaintOp bounds above needed to use the original 530 // coordinates (prior to any translation below) for relative 531 // paint processing. 532 dx1 += transX; 533 dy1 += transY; 534 dx2 += transX; 535 dy2 += transY; 536 // dh1 += transX; 537 dv1 += transY; 538 // dh2 += transX; 539 dv2 += transY; 540 } 541 542 float pw = tex.getPhysicalWidth(); 543 float ph = tex.getPhysicalHeight(); 544 float cx1 = tex.getContentX(); 545 float cy1 = tex.getContentY(); 546 float tx1 = (cx1 + sx1) / pw; 547 float ty1 = (cy1 + sy1) / ph; 548 float tx2 = (cx1 + sx2) / pw; 549 float ty2 = (cy1 + sy2) / ph; 550 // float th1 = (cx1 + sh1) / pw; 551 float tv1 = (cy1 + sv1) / ph; 552 // float th2 = (cx1 + sh2) / pw; 553 float tv2 = (cy1 + sv2) / ph; 554 555 VertexBuffer vb = context.getVertexBuffer(); 556 if (context.isSuperShaderEnabled()) { 557 vb.addSuperQuad(dx1, dy1, dx2, dv1, tx1, ty1, tx2, tv1, false); 558 vb.addSuperQuad(dx1, dv1, dx2, dv2, tx1, tv1, tx2, tv2, false); 559 vb.addSuperQuad(dx1, dv2, dx2, dy2, tx1, tv2, tx2, ty2, false); 560 } else { 561 vb.addQuad(dx1, dy1, dx2, dv1, tx1, ty1, tx2, tv1); 562 vb.addQuad(dx1, dv1, dx2, dv2, tx1, tv1, tx2, tv2); 563 vb.addQuad(dx1, dv2, dx2, dy2, tx1, tv2, tx2, ty2); 564 } 565 } 566 567 @Override 568 public void drawTexture9Slice(Texture tex, 569 float dx1, float dy1, float dx2, float dy2, 570 float sx1, float sy1, float sx2, float sy2, 571 float dh1, float dv1, float dh2, float dv2, 572 float sh1, float sv1, float sh2, float sv2) 573 { 574 BaseTransform xform = isSimpleTranslate ? IDENT : getTransformNoClone(); 575 PixelFormat format = tex.getPixelFormat(); 576 if (format == PixelFormat.BYTE_ALPHA) { 577 // Note that we treat this as a paint operation, using the 578 // given texture as the alpha mask; perhaps it would be better 579 // to treat this as a separate operation from drawTexture(), but 580 // overloading drawTexture() seems like an equally valid option. 581 context.validatePaintOp(this, xform, tex, dx1, dy1, dx2-dx1, dy2-dy1); 582 } else { 583 context.validateTextureOp(this, xform, tex, format); 584 } 585 if (isSimpleTranslate) { 586 // The validatePaintOp bounds above needed to use the original 587 // coordinates (prior to any translation below) for relative 588 // paint processing. 589 dx1 += transX; 590 dy1 += transY; 591 dx2 += transX; 592 dy2 += transY; 593 dh1 += transX; 594 dv1 += transY; 595 dh2 += transX; 596 dv2 += transY; 597 } 598 599 float pw = tex.getPhysicalWidth(); 600 float ph = tex.getPhysicalHeight(); 601 float cx1 = tex.getContentX(); 602 float cy1 = tex.getContentY(); 603 float tx1 = (cx1 + sx1) / pw; 604 float ty1 = (cy1 + sy1) / ph; 605 float tx2 = (cx1 + sx2) / pw; 606 float ty2 = (cy1 + sy2) / ph; 607 float th1 = (cx1 + sh1) / pw; 608 float tv1 = (cy1 + sv1) / ph; 609 float th2 = (cx1 + sh2) / pw; 610 float tv2 = (cy1 + sv2) / ph; 611 612 VertexBuffer vb = context.getVertexBuffer(); 613 if (context.isSuperShaderEnabled()) { 614 vb.addSuperQuad(dx1, dy1, dh1, dv1, tx1, ty1, th1, tv1, false); 615 vb.addSuperQuad(dh1, dy1, dh2, dv1, th1, ty1, th2, tv1, false); 616 vb.addSuperQuad(dh2, dy1, dx2, dv1, th2, ty1, tx2, tv1, false); 617 618 vb.addSuperQuad(dx1, dv1, dh1, dv2, tx1, tv1, th1, tv2, false); 619 vb.addSuperQuad(dh1, dv1, dh2, dv2, th1, tv1, th2, tv2, false); 620 vb.addSuperQuad(dh2, dv1, dx2, dv2, th2, tv1, tx2, tv2, false); 621 622 vb.addSuperQuad(dx1, dv2, dh1, dy2, tx1, tv2, th1, ty2, false); 623 vb.addSuperQuad(dh1, dv2, dh2, dy2, th1, tv2, th2, ty2, false); 624 vb.addSuperQuad(dh2, dv2, dx2, dy2, th2, tv2, tx2, ty2, false); 625 } else { 626 vb.addQuad(dx1, dy1, dh1, dv1, tx1, ty1, th1, tv1); 627 vb.addQuad(dh1, dy1, dh2, dv1, th1, ty1, th2, tv1); 628 vb.addQuad(dh2, dy1, dx2, dv1, th2, ty1, tx2, tv1); 629 630 vb.addQuad(dx1, dv1, dh1, dv2, tx1, tv1, th1, tv2); 631 vb.addQuad(dh1, dv1, dh2, dv2, th1, tv1, th2, tv2); 632 vb.addQuad(dh2, dv1, dx2, dv2, th2, tv1, tx2, tv2); 633 634 vb.addQuad(dx1, dv2, dh1, dy2, tx1, tv2, th1, ty2); 635 vb.addQuad(dh1, dv2, dh2, dy2, th1, tv2, th2, ty2); 636 vb.addQuad(dh2, dv2, dx2, dy2, th2, tv2, tx2, ty2); 637 } 638 } 639 640 public void drawTextureVO(Texture tex, 641 float topopacity, float botopacity, 642 float dx1, float dy1, float dx2, float dy2, 643 float sx1, float sy1, float sx2, float sy2) 644 { 645 BaseTransform xform = isSimpleTranslate ? IDENT : getTransformNoClone(); 646 PixelFormat format = tex.getPixelFormat(); 647 if (format == PixelFormat.BYTE_ALPHA) { 648 // Note that we treat this as a paint operation, using the 649 // given texture as the alpha mask; perhaps it would be better 650 // to treat this as a separate operation from drawTexture(), but 651 // overloading drawTexture() seems like an equally valid option. 652 context.validatePaintOp(this, xform, tex, dx1, dy1, dx2-dx1, dy2-dy1); 653 } else { 654 context.validateTextureOp(this, xform, tex, format); 655 } 656 if (isSimpleTranslate) { 657 // The validatePaintOp bounds above needed to use the original 658 // coordinates (prior to any translation below) for relative 659 // paint processing. 660 dx1 += transX; 661 dy1 += transY; 662 dx2 += transX; 663 dy2 += transY; 664 } 665 666 float tw = tex.getPhysicalWidth(); 667 float th = tex.getPhysicalHeight(); 668 float cx1 = tex.getContentX(); 669 float cy1 = tex.getContentY(); 670 float tx1 = (cx1 + sx1) / tw; 671 float ty1 = (cy1 + sy1) / th; 672 float tx2 = (cx1 + sx2) / tw; 673 float ty2 = (cy1 + sy2) / th; 674 675 VertexBuffer vb = context.getVertexBuffer(); 676 if (topopacity == 1f && botopacity == 1f) { 677 vb.addQuad(dx1, dy1, dx2, dy2, 678 tx1, ty1, tx2, ty2); 679 } else { 680 topopacity *= getExtraAlpha(); 681 botopacity *= getExtraAlpha(); 682 vb.addQuadVO(topopacity, botopacity, 683 dx1, dy1, dx2, dy2, 684 tx1, ty1, tx2, ty2); 685 } 686 } 687 688 public void drawTextureRaw(Texture tex, 689 float dx1, float dy1, float dx2, float dy2, 690 float tx1, float ty1, float tx2, float ty2) 691 { 692 // Capture the original bounds (prior to any translation below), 693 // which will be needed in the mask case. 694 // NOTE: note that we currently assume (here and throughout this 695 // method) that dx1<=dx2 and dy1<=dy2; the scenegraph does not rely 696 // on flipping behavior, but this method will need to be fixed if 697 // that assumption becomes invalid... 698 float bx = dx1; 699 float by = dy1; 700 float bw = dx2 - dx1; 701 float bh = dy2 - dy1; 702 703 // The following is safe; this method does not mutate the transform 704 BaseTransform xform = getTransformNoClone(); 705 if (isSimpleTranslate) { 706 xform = IDENT; 707 dx1 += transX; 708 dy1 += transY; 709 dx2 += transX; 710 dy2 += transY; 711 } 712 713 PixelFormat format = tex.getPixelFormat(); 714 if (format == PixelFormat.BYTE_ALPHA) { 715 // Note that we treat this as a paint operation, using the 716 // given texture as the alpha mask; perhaps it would be better 717 // to treat this as a separate operation from drawTexture(), but 718 // overloading drawTexture() seems like an equally valid option. 719 context.validatePaintOp(this, xform, tex, bx, by, bw, bh); 720 } else { 721 context.validateTextureOp(this, xform, tex, format); 722 } 723 724 VertexBuffer vb = context.getVertexBuffer(); 725 vb.addQuad(dx1, dy1, dx2, dy2, 726 tx1, ty1, tx2, ty2); 727 } 728 729 public void drawMappedTextureRaw(Texture tex, 730 float dx1, float dy1, float dx2, float dy2, 731 float tx11, float ty11, float tx21, float ty21, 732 float tx12, float ty12, float tx22, float ty22) 733 { 734 // Capture the original bounds (prior to any translation below), 735 // which will be needed in the mask case. 736 // NOTE: note that we currently assume (here and throughout this 737 // method) that dx1<=dx2 and dy1<=dy2; the scenegraph does not rely 738 // on flipping behavior, but this method will need to be fixed if 739 // that assumption becomes invalid... 740 float bx = dx1; 741 float by = dy1; 742 float bw = dx2 - dx1; 743 float bh = dy2 - dy1; 744 745 // The following is safe; this method does not mutate the transform 746 BaseTransform xform = getTransformNoClone(); 747 if (isSimpleTranslate) { 748 xform = IDENT; 749 dx1 += transX; 750 dy1 += transY; 751 dx2 += transX; 752 dy2 += transY; 753 } 754 755 PixelFormat format = tex.getPixelFormat(); 756 if (format == PixelFormat.BYTE_ALPHA) { 757 // Note that we treat this as a paint operation, using the 758 // given texture as the alpha mask; perhaps it would be better 759 // to treat this as a separate operation from drawTexture(), but 760 // overloading drawTexture() seems like an equally valid option. 761 context.validatePaintOp(this, xform, tex, bx, by, bw, bh); 762 } else { 763 context.validateTextureOp(this, xform, tex, format); 764 } 765 766 VertexBuffer vb = context.getVertexBuffer(); 767 vb.addMappedQuad(dx1, dy1, dx2, dy2, 768 tx11, ty11, tx21, ty21, 769 tx12, ty12, tx22, ty22); 770 } 771 772 }