Skip to content

Commit

Permalink
Making photon outline its own image to prevent over-rasterization, see
Browse files Browse the repository at this point in the history
  • Loading branch information
AgustinVallejo committed Jan 28, 2025
1 parent 3cc8ebd commit dfd06b8
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 24 deletions.
Binary file added images/greenPhotonOutline.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions images/greenPhotonOutline_png.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* eslint-disable */
/* @formatter:off */

import asyncLoader from '../../phet-core/js/asyncLoader.js';

const image = new Image();
const unlock = asyncLoader.createLock( image );
image.onload = unlock;
image.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADQAAAA0CAYAAADFeBvrAAAAx3pUWHRSYXcgcHJvZmlsZSB0eXBlIGV4aWYAAHjabVDbDcMwCPxnio5gwA88jtMkUjfo+AVDoiTqST5jDp8xsH0/O7wMhBlyaVJ7rUmRe+40NJDkGJMx5ckTnEPDex5OgTTFVulHqVF/5PE08G1oVC5G8g5huQs9HiB5GFF0Zh1ZvIZRDyMmFzAMhn8r1S7t+oVlS3eILzBadu3HZhSXn+fcdHpr0XeYaGPkpMws3gDbKsBDA1QmblY448JdGblGJzqQf3M6AD+qr1qnvX/rkgAAAYNpQ0NQSUNDIHByb2ZpbGUAAHicfZE9SMNQFIVPE6UiFQc7iHTIUJ3soiKOpYpFsFDaCq06mLz0D5o0JCkujoJrwcGfxaqDi7OuDq6CIPgD4i44KbpIifclhRYxXnjwcd49l/vOA4RWjWlWXxzQdNvMJBNSvrAqBV8RQAQCYhBlZhmp7GIOvvV1T91UdzE+y7/vzxpSixYDAhJxnBmmTbxBPLtpG5z3icOsIqvE58STJi1I/Mh1xeM3zmWXBT4zbOYy88RhYqncw0oPs4qpEc8QR1VNp/lC3mOV8xZnrdZgnT35C0NFfSXLdToRJLGEFNKQoKCBKmqwKa8qdFIsZOg+4eMfc/1pcinkqoKRYwF1aJBdP/gf/M7WKk1PeZNCCaD/xXE+xoHgLtBuOs73seO0TwDxGbjSu/56C5j7JL3Z1aJHwPA2cHHd1ZQ94HIHGH0yZFN2JZGOUCoB72f0TQVg5BYYXPNy69zj9AHIUVbLN8DBITBRptnrPu8e6M3t355Ofj+F6HKubQTE6QAADXZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+Cjx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDQuNC4wLUV4aXYyIj4KIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIKICAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgIHhtbG5zOkdJTVA9Imh0dHA6Ly93d3cuZ2ltcC5vcmcveG1wLyIKICAgIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIgogICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICB4bXBNTTpEb2N1bWVudElEPSJnaW1wOmRvY2lkOmdpbXA6OGYzZGNlM2UtNTNkZC00N2QxLThlY2ItZDM4ZDhkMDI3YzJhIgogICB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjVmN2U0NThkLWU0ZjQtNDkxZC05NjVhLTIwZmIwODY2ZmE0NyIKICAgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjY0ZmU1YTkyLWQ4ZGYtNGRjZS1hMTMyLWZkYzA1MDljMjhhYiIKICAgZGM6Rm9ybWF0PSJpbWFnZS9wbmciCiAgIEdJTVA6QVBJPSIyLjAiCiAgIEdJTVA6UGxhdGZvcm09IldpbmRvd3MiCiAgIEdJTVA6VGltZVN0YW1wPSIxNzM4MDMzMTU2ODczNzk3IgogICBHSU1QOlZlcnNpb249IjIuMTAuMzgiCiAgIHRpZmY6T3JpZW50YXRpb249IjEiCiAgIHhtcDpDcmVhdG9yVG9vbD0iR0lNUCAyLjEwIgogICB4bXA6TWV0YWRhdGFEYXRlPSIyMDI1OjAxOjI3VDIxOjU5OjE2LTA1OjAwIgogICB4bXA6TW9kaWZ5RGF0ZT0iMjAyNTowMToyN1QyMTo1OToxNi0wNTowMCI+CiAgIDx4bXBNTTpIaXN0b3J5PgogICAgPHJkZjpTZXE+CiAgICAgPHJkZjpsaQogICAgICBzdEV2dDphY3Rpb249InNhdmVkIgogICAgICBzdEV2dDpjaGFuZ2VkPSIvIgogICAgICBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjBlMGFmMzAzLTQyZWYtNGFmOS1hNmVhLTJkMjE5MDVjNjEzNiIKICAgICAgc3RFdnQ6c29mdHdhcmVBZ2VudD0iR2ltcCAyLjEwIChXaW5kb3dzKSIKICAgICAgc3RFdnQ6d2hlbj0iMjAyNS0wMS0yN1QyMTo1OToxNiIvPgogICAgPC9yZGY6U2VxPgogICA8L3htcE1NOkhpc3Rvcnk+CiAgPC9yZGY6RGVzY3JpcHRpb24+CiA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgCjw/eHBhY2tldCBlbmQ9InciPz4vNlQCAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAB3RJTUUH6QEcAjsQ+LEKTwAAArhJREFUaN7tmj9v00AUwH/neOhAUQUFqSMTysJChnyJDnwAJJaOWTv0C1R8CgZAbDAh1BUJKfwTKEukCrWgIkWpU7VCjSpKksfAhboX25fEJrmLeKcbLNvn9/N7fr737qBIER4jRAg9xNp6CB2EpzglwjuE/hgAttZH+JBXHZUDJAJW/9FrOkJNN7aaAmQPuGW56gVQB5pAyzi3BpSBKnDPMs5XlPVZU1ukZnGt5wgVhGWEEKGEECAoowf6XKivreh7s1yxVjRMIwNiHeGGVlBN2UM9xnoGXKMomCjlAZv6DQc5QJKst6zHTmpRXpiTDNcKCwRJsliaK54UaZmhVdSMepq1oiK+mU2EpRnCDPtSClRjkmjmCowNqjYOUN8xmCyovg1mPyEALDsAE/+mzECxlwVktopDMMNeGdEyBaaT4Gqhg0BhgutFNuu45mp219MSaBhz2v4I6OKudLWOcYO8v5ht/4kWQez0TaCD27IKHMaOByhKwSVLXUz9j3FfjrWul70N4ZkHkW3ciPdEIRwB12KkV4FT/JArwI94phsAK4a7neGPnBlutxIY308d0n5UToponYdSCowLmh4CNRmNDH+l5SFQKwvIe/kP5BvQWq5q6uxFaZ1TgcoeApVNoHgaW/UQqBo77iuEDnB9kaY+O8ZFtz2ykKnrTlq2Gnow0w6TstaFTfDMFNz14GAGA4CPC1kkiQO1PS5jtRe20GjOFHaN4y0d613672xZdB6x0i+PivW9cVKmDY+WUzbGzQPferDgVZ80uf3u8JLkwbQZ+6GDi8btvGWIA4eW9b8VVVt5gzCY48aLAcLrogtGDxDO57A15hzh/iSTvEnBPgN3LPcWsXlJgE8o7s6qxLef4oZ52wDhyzxrl68srjhu+4nw0rXC7EOEXYSuZStaD+EUoYmwXaQKvwGmIh2e839ouAAAAABJRU5ErkJggg==';
export default image;
8 changes: 8 additions & 0 deletions images/license.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,13 @@
"projectURL": "https://phet.colorado.edu",
"license": "contact [email protected]",
"notes": "created by John Blanco"
},
"greenPhotonOutline.png": {
"text": [
"Copyright 2023 University of Colorado Boulder"
],
"projectURL": "https://phet.colorado.edu",
"license": "contact [email protected]",
"notes": "created by Agustín Vallejo"
}
}
40 changes: 16 additions & 24 deletions js/photons/view/PhotonSprites.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
import Bounds2 from '../../../../dot/js/Bounds2.js';
import Vector2 from '../../../../dot/js/Vector2.js';
import ModelViewTransform2 from '../../../../phetcommon/js/view/ModelViewTransform2.js';
import { Circle, Sprite, SpriteImage, SpriteInstance, SpriteInstanceTransformType, Sprites } from '../../../../scenery/js/imports.js';
import { Sprite, SpriteImage, SpriteInstance, SpriteInstanceTransformType, Sprites } from '../../../../scenery/js/imports.js';
import greenPhoton_png from '../../../images/greenPhoton_png.js';
import QuantumMeasurementColors from '../../common/QuantumMeasurementColors.js';
import greenPhotonOutline_png from '../../../images/greenPhotonOutline_png.js';
import quantumMeasurement from '../../quantumMeasurement.js';
import Photon from '../model/Photon.js';

Expand All @@ -34,8 +34,8 @@ class PhotonSprites extends Sprites {
private readonly photons: Photon[];
private readonly modelViewTransform: ModelViewTransform2;

// The scale value used to render the photon interior.
private readonly photonInteriorScale: number;
// The scale value used to render the photon.
private readonly photonScale: number;

// The sprites used to render the photons.
private readonly photonInteriorSprite: Sprite | null = null;
Expand All @@ -62,29 +62,21 @@ class PhotonSprites extends Sprites {
new Vector2( greenPhoton_png.width / 2, greenPhoton_png.height / 2 ),
{ pickable: false }
) );
this.photonOutlineSprite = new Sprite( new SpriteImage(
greenPhotonOutline_png,
new Vector2( greenPhotonOutline_png.width / 2, greenPhotonOutline_png.height / 2 ),
{ pickable: false }
) );
this.mutate( { sprites: [ this.photonInteriorSprite, this.photonOutlineSprite ] } );

// Calculate the scale that will be used to render the photon interior.
this.photonInteriorScale = TARGET_PHOTON_VIEW_WIDTH / greenPhoton_png.width;
this.photonScale = TARGET_PHOTON_VIEW_WIDTH / greenPhoton_png.width;

assert && assert(
this.photonInteriorScale > 0 && this.photonInteriorScale < 100,
`photon scale factor not reasonable: ${this.photonInteriorScale}`
this.photonScale > 0 && this.photonScale < 100,
`photon scale factor not reasonable: ${this.photonScale}`
);

// Create the sprite for the outline of the photons. This is done be creating a circle and rendering it to a
// canvas. That is an asynchronous process, so we need to wait for it to complete before adding the sprites.
const outlineCircle = new Circle( TARGET_PHOTON_VIEW_WIDTH / 2, {
stroke: QuantumMeasurementColors.photonBaseColorProperty.value,
lineWidth: 1
} );
outlineCircle.toCanvas( canvas => {
this.photonOutlineSprite = new Sprite( new SpriteImage(
canvas,
new Vector2( canvas.width / 2, canvas.height / 2 ),
{ pickable: false }
) );
this.mutate( { sprites: [ this.photonInteriorSprite!, this.photonOutlineSprite ] } );
} );

// local variables needed for the methods
this.spriteInstances = spriteInstances;
this.photons = photons;
Expand Down Expand Up @@ -130,7 +122,7 @@ class PhotonSprites extends Sprites {

const xPos = this.modelViewTransform.modelToViewX( photonStatePosition.x );
const yPos = this.modelViewTransform.modelToViewY( photonStatePosition.y );
const scale = this.photonInteriorScale;
const scale = this.photonScale;

// Update the matrix and opacity for the photon interior.
const interiorSpriteInstance = this.spriteInstances[ ( numberOfPhotonsDisplayed - 1 ) * 2 ];
Expand All @@ -141,7 +133,7 @@ class PhotonSprites extends Sprites {
// Update the matrix for the photon outline.
const outlineSpriteInstance = this.spriteInstances[ ( numberOfPhotonsDisplayed - 1 ) * 2 + 1 ];
outlineSpriteInstance.sprite = this.photonOutlineSprite;
outlineSpriteInstance.matrix.setToAffine( 1, 0, xPos, 0, 1, yPos );
outlineSpriteInstance.matrix.setToAffine( scale, 0, xPos, 0, scale, yPos );
outlineSpriteInstance.alpha = 1; // Always fully opaque
}
}
Expand Down

0 comments on commit dfd06b8

Please sign in to comment.