From 6d02415ef3930453602ca66b1f7db2b749e039d3 Mon Sep 17 00:00:00 2001 From: Jesse Date: Thu, 23 May 2019 12:53:21 -0400 Subject: [PATCH] remove webgl nodes for pie chart, see #66 --- .../common/view/CircularOutlineWebGLNode.js | 218 ------------------ .../view/PieChartWebGLNode.js | 164 ------------- .../view/PieChartWebGLSliceNode.js | 197 ---------------- 3 files changed, 579 deletions(-) delete mode 100644 js/energy-skate-park/common/view/CircularOutlineWebGLNode.js delete mode 100644 js/energy-skate-park/view/PieChartWebGLNode.js delete mode 100644 js/energy-skate-park/view/PieChartWebGLSliceNode.js diff --git a/js/energy-skate-park/common/view/CircularOutlineWebGLNode.js b/js/energy-skate-park/common/view/CircularOutlineWebGLNode.js deleted file mode 100644 index ab309af6..00000000 --- a/js/energy-skate-park/common/view/CircularOutlineWebGLNode.js +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2018-2019, University of Colorado Boulder - -/** - * Dashed outline for a circle using WebGLNode. Many portions of this file are quite similar to PieChartWebGLSliceNode, - * so we could consider turning into a single type in the near future. (Like adding a glLineDash option to that node - * and moving the implementation there?) - * - * @author Jesse Greenberg - */ - -define( function( require ) { - 'use strict'; - - // modules - var Bounds2 = require( 'DOT/Bounds2' ); - var Color = require( 'SCENERY/util/Color' ); - var energySkatePark = require( 'ENERGY_SKATE_PARK/energySkatePark' ); - var inherit = require( 'PHET_CORE/inherit' ); - var ShaderProgram = require( 'SCENERY/util/ShaderProgram' ); - var Util = require( 'DOT/Util' ); - var WebGLNode = require( 'SCENERY/nodes/WebGLNode' ); - - // constants - // specific to the vertex data implementation - var POINTS_PER_VERTEX = 2; - var scratchFloatArray = new Float32Array( 9 ); - - /** - * @constructor - * @param {Color} color - * @param {NumberProperty} radiusProperty - */ - function CircularOutlineWebGLNode( color, radiusProperty ) { - var self = this; - - // @private (inner-type) assign color, to be used in the painter - this.color = Color.toColor( color ); - this.radiusProperty = radiusProperty; - - WebGLNode.call( this, OutlinePainter, { - canvasBounds: new Bounds2( 0, 0, 100, 100 ) - } ); - - // when radius changes, set the scale accordingly and repaint - this.radiusProperty.link( function( radius ) { - if ( radius > 0 ) { - self.setScaleMagnitude( radius * 2, radius * 2 ); - } - else { - self.setScaleMagnitude( Math.sqrt( 2 ) / 2, Math.sqrt( 2 ) / 2 ); - } - self.invalidatePaint(); - } ); - - this.invalidatePaint(); - } - - energySkatePark.register( 'CircularOutlineWebGLNode', CircularOutlineWebGLNode ); - - inherit( WebGLNode, CircularOutlineWebGLNode, { - - /** - * Mark the WebGL flag as dirty, to ensure that it will render. - * - * @param {number} dt - */ - step: function( dt ) { - this.invalidatePaint(); - } - } ); - - /** - * Painter used by the WebGLNode. - * - * @constructor - * @param {WebGLRenderingContext} gl - * @param {Node} node - WebGLNode using this painter - */ - function OutlinePainter( gl, node ) { - this.gl = gl; - this.node = node; - - // basic vertex shader with position and color - var vertexShaderSource = [ - // Position - 'attribute vec2 aPosition;', - 'uniform vec4 uColor;', - 'varying vec4 vColor;', - 'uniform mat3 uModelViewMatrix;', - 'uniform mat3 uProjectionMatrix;', - - 'void main( void ) {', - ' vColor = uColor;', - // homogeneous model-view transformation - ' vec3 view = uModelViewMatrix * vec3( aPosition.xy, 1 );', - // homogeneous map to to normalized device coordinates - ' vec3 ndc = uProjectionMatrix * vec3( view.xy, 1 );', - // combine with the z coordinate specified - ' gl_Position = vec4( ndc.xy, 0.2, 1.0 );', - '}' - ].join( '\n' ); - - // basic fragment shader receiving color - var fragmentShaderSource = [ - 'precision mediump float;', - 'varying vec4 vColor;', - - // Returns the color from the vertex shader - 'void main( void ) {', - ' gl_FragColor = vColor;', - - // Use premultipled alpha, see https://github.com/phetsims/energy-skate-park/issues/39 - ' gl_FragColor.rgb *= gl_FragColor.a;', - '}' - ].join( '\n' ); - - this.shaderProgram = new ShaderProgram( gl, vertexShaderSource, fragmentShaderSource, { - attributes: [ 'aPosition' ], - uniforms: [ 'uModelViewMatrix', 'uProjectionMatrix', 'uColor' ] - } ); - - this.vertexBuffer = gl.createBuffer(); - - // we will use gl.TRIANGLES to draw sections of triangles that create - // a dashed outline - var outerRadius = 0.5; - var innerRadius = 0.46; - - var fullCircle = Math.PI * 2; - var numSections = 40; - var delta = fullCircle / numSections; - - // samples used to create a smooth looking circle - var numSamples = 400; - - this.vertices = []; - for ( var i = 0; i < numSamples; i++ ) { - var angle = fullCircle / numSamples * i; - - // vertex to the inner radius - var x = innerRadius * Math.cos( angle ); - var y = innerRadius * Math.sin( angle ); - this.vertices.push( x ); - this.vertices.push( y ); - - // round angle to nearest section - var section = Math.floor( angle / delta ) * delta; - - // determine if section is even out of the total sections - if so we will include this triangle - var evenSection = Util.roundSymmetric( ( section / fullCircle ) * numSections ) % 2 === 0; - - if ( evenSection ) { - - // vertex to the outer radius - x = outerRadius * Math.cos( angle ); - y = outerRadius * Math.sin( angle ); - this.vertices.push( x ); - this.vertices.push( y ); - } - else { - - // duplicate of the innner radius to produce stroke of 0 height along the parts where we don't want to see - // a dash - this.vertices.push( x ); - this.vertices.push( y ); - } - } - - gl.bindBuffer( gl.ARRAY_BUFFER, this.vertexBuffer ); - gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( this.vertices ), gl.STATIC_DRAW ); - } - - energySkatePark.register( 'OutlinePainter', OutlinePainter ); - - inherit( Object, OutlinePainter, { - - /** - * Called from within the swirling depths of scenery. - * - * @param {Matrix3} modelViewMatrix - * @param {Matrix3} projectionMatrix - * - * @returns {number} - flag describing purpose of this function. - */ - paint: function( modelViewMatrix, projectionMatrix ) { - var gl = this.gl; - var shaderProgram = this.shaderProgram; - - shaderProgram.use(); - - gl.uniformMatrix3fv( shaderProgram.uniformLocations.uModelViewMatrix, false, modelViewMatrix.copyToArray( scratchFloatArray ) ); - gl.uniformMatrix3fv( shaderProgram.uniformLocations.uProjectionMatrix, false, projectionMatrix.copyToArray( scratchFloatArray ) ); - - gl.bindBuffer( gl.ARRAY_BUFFER, this.vertexBuffer ); - gl.vertexAttribPointer( shaderProgram.attributeLocations.aPosition, 2, gl.FLOAT, false, 0, 0 ); - - var color = this.node.color; - gl.uniform4f( shaderProgram.uniformLocations.uColor, color.r / 255, color.g / 255, color.b / 255, color.a ); - - // draw, one triangle per vertex and subtract one triangle so we don't overflow - gl.drawArrays( gl.TRIANGLE_STRIP, 0, ( this.vertices.length / POINTS_PER_VERTEX ) ); - shaderProgram.unuse(); - - return WebGLNode.PAINTED_SOMETHING; - }, - - /** - * Clear the painter and WebGL resources. - */ - dispose: function() { - this.shaderProgram.dispose(); - this.gl.deleteBuffer( this.vertexBuffer ); - this.shaderProgram = null; - } - } ); - - return CircularOutlineWebGLNode; -} ); diff --git a/js/energy-skate-park/view/PieChartWebGLNode.js b/js/energy-skate-park/view/PieChartWebGLNode.js deleted file mode 100644 index 998e8809..00000000 --- a/js/energy-skate-park/view/PieChartWebGLNode.js +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2014-2019, University of Colorado Boulder - -/** - * Pie chart, rendered in WebGL to improve performance (when WebGL available) - * - * @author Sam Reid (PhET Interactive Simulations) - */ -define( function( require ) { - 'use strict'; - - // modules - var CircularOutlineWebGLNode = require( 'ENERGY_SKATE_PARK/energy-skate-park/common/view/CircularOutlineWebGLNode' ); - var DerivedProperty = require( 'AXON/DerivedProperty' ); - var energySkatePark = require( 'ENERGY_SKATE_PARK/energySkatePark' ); - var EnergySkateParkColorScheme = require( 'ENERGY_SKATE_PARK/energy-skate-park/view/EnergySkateParkColorScheme' ); - var inherit = require( 'PHET_CORE/inherit' ); - var Node = require( 'SCENERY/nodes/Node' ); - var PieChartWebGLSliceNode = require( 'ENERGY_SKATE_PARK/energy-skate-park/view/PieChartWebGLSliceNode' ); - var Property = require( 'AXON/Property' ); - - /** - * @param {Skater} skater the skater model - * @param {Property} pieChartVisibleProperty axon Property indicating whether the pie chart is shown - * @param {ModelViewTransform2} modelViewTransform - * @constructor - */ - function PieChartWebGLNode( skater, pieChartVisibleProperty, modelViewTransform, tandem ) { - - var self = this; - Node.call( this, { - tandem: tandem - } ); - - // Show the pie chart above the skater's head - Property.multilink( [ skater.headPositionProperty, pieChartVisibleProperty ], function( skaterHeadPosition, pieChartVisible ) { - - // Only update it when visible, to improve performance - if ( pieChartVisible ) { - var view = modelViewTransform.modelToViewPosition( skaterHeadPosition ); - - // Center pie chart over skater's head not his feet so it doesn't look awkward when skating in a parabola - self.setTranslation( view.x, view.y - 50 ); - } - } ); - - // Make the radius proportional to the square root of the energy so that the area will grow linearly with energy, - // taking the absolute value to handle when skater is below the potential energy reference line - var pieChartRadiusProperty = new DerivedProperty( [ skater.totalEnergyProperty ], function( totalEnergy ) { - return 0.4 * Math.sqrt( Math.abs( totalEnergy ) ); - } ); - - var potentialEnergyProportion = new DerivedProperty( [ skater.potentialEnergyProperty, skater.totalEnergyProperty ], function( potentialEnergy, totalEnergy ) { - var result = totalEnergy === 0 ? 0 : (potentialEnergy / totalEnergy); - var clamped = result < 0 ? 0 : - result > 1 ? 1 : - result; - assert && assert( !isNaN( clamped ), 'should be a number!' ); - return clamped * Math.PI * 2; - } ); - - var kineticEnergyProportion = new DerivedProperty( [ skater.kineticEnergyProperty, skater.totalEnergyProperty ], function( kineticEnergy, totalEnergy ) { - var result = totalEnergy === 0 ? 0 : (kineticEnergy / totalEnergy); - var clamped = result < 0 ? 0 : - result > 1 ? 1 : - result; - assert && assert( !isNaN( clamped ), 'should be a number!' ); - return clamped * Math.PI * 2; - } ); - - var thermalEnergyProportion = new DerivedProperty( [ skater.thermalEnergyProperty, skater.totalEnergyProperty ], function( thermalEnergy, totalEnergy ) { - var result = totalEnergy === 0 ? 0 : (thermalEnergy / totalEnergy); - var clamped = result < 0 ? 0 : - result > 1 ? 1 : - result; - var number = clamped * Math.PI * 2; - assert && assert( !isNaN( number ), 'should be a number!' ); - return number; - } ); - - var plus = function( a, b ) { - return new DerivedProperty( [ a, b ], function( a, b ) { - return a + b; - } ); - }; - - var pieStroke = 1; - - // TODO: why did Property.multilink not work here? - var outlineRadiusProperty = new DerivedProperty( [ pieChartRadiusProperty ], function( pieChartRadius ) { - - // If any slice is too small, then don't show it. Use the same rules as the non-webgl pie chart, see #136 - if ( pieChartRadius <= 0.05 ) { - return 0; - } - else { - return pieChartRadius + pieStroke; - } - } ); - - // // Render the stroke as a larger black circle behind the pie chart - var outline = new PieChartWebGLSliceNode( - 'black', - outlineRadiusProperty, - new Property( Math.PI * 2 ) - ); - - var thermalEnergyPiece = new PieChartWebGLSliceNode( - EnergySkateParkColorScheme.thermalEnergy, - pieChartRadiusProperty, - thermalEnergyProportion - ); - - var kineticEnergyPiece = new PieChartWebGLSliceNode( - EnergySkateParkColorScheme.kineticEnergy, - pieChartRadiusProperty, - plus( thermalEnergyProportion, kineticEnergyProportion ) - ); - - var potentialEnergyPiece = new PieChartWebGLSliceNode( - EnergySkateParkColorScheme.potentialEnergy, - pieChartRadiusProperty, - plus( plus( kineticEnergyProportion, thermalEnergyProportion ), potentialEnergyProportion ) - ); - - var totalEnergyPiece = new PieChartWebGLSliceNode( - EnergySkateParkColorScheme.totalEnergy.withAlpha( 0.5 ), - pieChartRadiusProperty, - new Property( Math.PI * 2 ) - ); - - var circularOutline = new CircularOutlineWebGLNode( 'rgba(0,0,0,0.5)', outlineRadiusProperty ); - - // energy pieces need to be on top of the "outlines" - this.addChild( outline ); - this.addChild( circularOutline ); - - this.addChild( potentialEnergyPiece ); - this.addChild( kineticEnergyPiece ); - this.addChild( thermalEnergyPiece ); - this.addChild( totalEnergyPiece ); - - pieChartVisibleProperty.linkAttribute( this, 'visible' ); - - // when potential energy is negative, we will show the total energy as a transparent circle since pie charts - // don't easily represent negative values - skater.potentialEnergyProperty.link( function( potentialEnergy ) { - - var energyNonnegative = potentialEnergy >= 0; - - outline.visible = energyNonnegative; - potentialEnergyPiece.visible = energyNonnegative; - kineticEnergyPiece.visible = energyNonnegative; - thermalEnergyPiece.visible = energyNonnegative; - - circularOutline.visible = !energyNonnegative; - totalEnergyPiece.visible = !energyNonnegative; - - } ); - } - - energySkatePark.register( 'PieChartWebGLNode', PieChartWebGLNode ); - - return inherit( Node, PieChartWebGLNode ); -} ); \ No newline at end of file diff --git a/js/energy-skate-park/view/PieChartWebGLSliceNode.js b/js/energy-skate-park/view/PieChartWebGLSliceNode.js deleted file mode 100644 index 6e286f84..00000000 --- a/js/energy-skate-park/view/PieChartWebGLSliceNode.js +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright 2014-2019, University of Colorado Boulder - -/** - * A single slice of a pie chart, as contained in PieChartWebGLNode. The slices each start at angle=0 and overlap each other, so the - * z-ordering is critical. - * - * @author Sam Reid (PhET Interactive Simulations) - */ -define( function( require ) { - 'use strict'; - - // modules - var Bounds2 = require( 'DOT/Bounds2' ); - var Color = require( 'SCENERY/util/Color' ); - var energySkatePark = require( 'ENERGY_SKATE_PARK/energySkatePark' ); - var inherit = require( 'PHET_CORE/inherit' ); - var ShaderProgram = require( 'SCENERY/util/ShaderProgram' ); - var Shape = require( 'KITE/Shape' ); - var Util = require( 'DOT/Util' ); - var WebGLNode = require( 'SCENERY/nodes/WebGLNode' ); - - // constants - var scratchFloatArray = new Float32Array( 9 ); - - /** - * @param {Color} color - * @param {Property} radiusProperty - * @param {Property} extentProperty - * @constructor - */ - function PieChartWebGLSliceNode( color, radiusProperty, extentProperty ) { - var self = this; - this.color = Color.toColor( color ); - this.radiusProperty = radiusProperty; - this.extentProperty = extentProperty; - WebGLNode.call( this, PieChartSlicePainter, { canvasBounds: new Bounds2( 0, 0, 100, 100 ) } ); - - this.invalidatePaint(); - - this.shape = Shape.regularPolygon( 3, 100 * Math.sqrt( 2 ) ); - this.radiusProperty.link( function( radius ) { - if ( radius > 0 ) { - self.setScaleMagnitude( radius * 2, radius * 2 ); - } - else { - self.setScaleMagnitude( Math.sqrt( 2 ) / 2, Math.sqrt( 2 ) / 2 ); - } - self.invalidatePaint(); - } ); - this.extentProperty.link( function() { - self.invalidatePaint(); - } ); - } - - energySkatePark.register( 'PieChartWebGLSliceNode', PieChartWebGLSliceNode ); - - inherit( WebGLNode, PieChartWebGLSliceNode, { - step: function( dt ) { - // Mark the WebGL dirty flag as dirty, to ensure it will render. - this.invalidatePaint(); - } - } ); - - /** - * @constructor - * - * @param {WebGLRenderingContext} gl - * @param {WaveWebGLNode} node - */ - function PieChartSlicePainter( gl, node ) { - assert && assert( typeof gl !== 'string', 'gl should not be a string' ); - this.gl = gl; - this.node = node; - - // Simple example for custom shader - var vertexShaderSource = [ - // Position - 'attribute vec2 aPosition;', - 'uniform vec4 uColor;', - 'varying vec4 vColor;', - 'uniform mat3 uModelViewMatrix;', - 'uniform mat3 uProjectionMatrix;', - - 'void main( void ) {', - ' vColor = uColor;', - // homogeneous model-view transformation - ' vec3 view = uModelViewMatrix * vec3( aPosition.xy, 1 );', - // homogeneous map to to normalized device coordinates - ' vec3 ndc = uProjectionMatrix * vec3( view.xy, 1 );', - // combine with the z coordinate specified - ' gl_Position = vec4( ndc.xy, 0.2, 1.0 );', - '}' - ].join( '\n' ); - - // Simple demo for custom shader - var fragmentShaderSource = [ - 'precision mediump float;', - 'varying vec4 vColor;', - - // Returns the color from the vertex shader - 'void main( void ) {', - ' gl_FragColor = vColor;', - - // Use premultipled alpha, see https://github.com/phetsims/energy-skate-park/issues/39 - ' gl_FragColor.rgb *= gl_FragColor.a;', - '}' - ].join( '\n' ); - - this.shaderProgram = new ShaderProgram( gl, vertexShaderSource, fragmentShaderSource, { - attributes: [ 'aPosition' ], - uniforms: [ 'uModelViewMatrix', 'uProjectionMatrix', 'uColor' ] - } ); - - this.vertexBuffer = gl.createBuffer(); - - var centerX = 0; - var centerY = 0; - var radius = 0.5; - - // 40 makes a smooth circle, but we need enough samples to eliminate seams between the pie slices - // Win8/Chrome starts to slow down around 1000000 samples - // But need it to be high enough that we don't see discrete jumps when the energy changes, see #303 - var numSamples = 1000; - this.numSamples = numSamples; - - var vertices = [ centerX, centerY ]; - this.vertices = vertices; - - var indexToVertex = function( i ) { - var angle = -Math.PI * 2 / numSamples * i; - var x = radius * Math.cos( angle ) + centerX; - var y = radius * Math.sin( angle ) + centerY; - vertices.push( x ); - vertices.push( y ); - }; - - //Go back to the first vertex, to make sure it is a closed circle - for ( var i = 0; i <= numSamples; i++ ) { - indexToVertex( i ); - } - - // var points = this.shape.subpaths[ 0 ].points; - gl.bindBuffer( gl.ARRAY_BUFFER, this.vertexBuffer ); - gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( vertices ), gl.STATIC_DRAW ); - } - - energySkatePark.register( 'PieChartSlicePainter', PieChartSlicePainter ); - - inherit( Object, PieChartSlicePainter, { - paint: function( modelViewMatrix, projectionMatrix ) { - var gl = this.gl; - var shaderProgram = this.shaderProgram; - - shaderProgram.use(); - - gl.uniformMatrix3fv( shaderProgram.uniformLocations.uModelViewMatrix, false, modelViewMatrix.copyToArray( scratchFloatArray ) ); - gl.uniformMatrix3fv( shaderProgram.uniformLocations.uProjectionMatrix, false, projectionMatrix.copyToArray( scratchFloatArray ) ); - - gl.bindBuffer( gl.ARRAY_BUFFER, this.vertexBuffer ); - gl.vertexAttribPointer( shaderProgram.attributeLocations.aPosition, 2, gl.FLOAT, false, 0, 0 ); - - var color = this.node.color; - gl.uniform4f( shaderProgram.uniformLocations.uColor, color.r / 255, color.g / 255, color.b / 255, color.a ); - - var angleBetweenSlices = Math.PI * 2 / this.numSamples; - - //Round to the nearest angle to prevent seams, see #263 - var startAngle = 0; - var unroundedEndAngle = this.node.extentProperty.value; - var endAngle = Util.roundSymmetric( unroundedEndAngle / angleBetweenSlices ) * angleBetweenSlices; - - var extent = endAngle - startAngle; - - // To cut out a piece from the pie, just select the appropriate start/end vertices, then the call is still static. - var numToDraw = Util.roundSymmetric( 2 + ( this.vertices.length / 2 - 2 ) * extent / ( 2 * Math.PI ) ); // linear between 2 and the maximum - - // Make sure to show non-zero energy if the value is above the threshold, see #307 - if ( numToDraw === 2 && this.node.extentProperty.get() > 1E-6 ) { - numToDraw = 3; - } - - gl.drawArrays( gl.TRIANGLE_FAN, 0, numToDraw ); - shaderProgram.unuse(); - - return WebGLNode.PAINTED_SOMETHING; - }, - - dispose: function() { - // clears all of our resources - this.shaderProgram.dispose(); - this.gl.deleteBuffer( this.vertexBuffer ); - this.shaderProgram = null; - } - } ); - - return PieChartWebGLSliceNode; -} ); \ No newline at end of file