@@ -2,6 +2,7 @@ var $ = require('jquery');
22var inherit = require ( '../inherit' ) ;
33var registerFeature = require ( '../registry' ) . registerFeature ;
44var pointFeature = require ( '../pointFeature' ) ;
5+ var webglRenderer = require ( './webglRenderer' ) ;
56
67/**
78 * Create a new instance of webgl.pointFeature.
@@ -41,23 +42,22 @@ var webgl_pointFeature = function (arg) {
4142 m_pixelWidthUniform = null ,
4243 m_aspectUniform = null ,
4344 m_dynamicDraw = arg . dynamicDraw === undefined ? false : arg . dynamicDraw ,
44- /* If you are drawing very large points, you will often get better
45- * performance using a different primitiveShape. The 'sprite' shape uses
46- * the least memory, but has hardware-specific limitations to its size.
47- * 'triangle' seems to be fastest on low-powered hardware, but 'square'
48- * visits fewer fragments. */
49- m_primitiveShape = 'sprite' , // arg can change this, below
45+ m_primitiveShapeAuto = true ,
46+ m_primitiveShape = pointFeature . primitiveShapes . auto , // arg can change this, below
5047 m_modelViewUniform ,
5148 m_origin ,
5249 s_init = this . _init ,
5350 s_update = this . _update ,
5451 s_updateStyleFromArray = this . updateStyleFromArray ;
5552
56- if ( arg . primitiveShape === 'triangle' ||
57- arg . primitiveShape === 'square' ||
58- arg . primitiveShape === 'sprite' ) {
53+ if ( pointFeature . primitiveShapes [ arg . primitiveShape ] !== undefined ) {
5954 m_primitiveShape = arg . primitiveShape ;
6055 }
56+ m_primitiveShapeAuto = m_primitiveShape === pointFeature . primitiveShapes . auto ;
57+ if ( m_primitiveShapeAuto ) {
58+ m_primitiveShape = pointFeature . primitiveShapes . sprite ;
59+ m_primitiveShapeAuto = true ;
60+ }
6161
6262 /**
6363 * Create the vertex shader for points.
@@ -67,7 +67,7 @@ var webgl_pointFeature = function (arg) {
6767 function createVertexShader ( ) {
6868 var shader = new vgl . shader ( vgl . GL . VERTEX_SHADER ) ;
6969 shader . setShaderSource (
70- m_primitiveShape === ' sprite' ? vertexShaderSprite : vertexShaderPoly ) ;
70+ m_primitiveShape === pointFeature . primitiveShapes . sprite ? vertexShaderSprite : vertexShaderPoly ) ;
7171 return shader ;
7272 }
7373
@@ -79,7 +79,7 @@ var webgl_pointFeature = function (arg) {
7979 function createFragmentShader ( ) {
8080 var shader = new vgl . shader ( vgl . GL . FRAGMENT_SHADER ) ;
8181 shader . setShaderSource (
82- m_primitiveShape === ' sprite' ? fragmentShaderSprite : fragmentShaderPoly ) ;
82+ m_primitiveShape === pointFeature . primitiveShapes . sprite ? fragmentShaderSprite : fragmentShaderPoly ) ;
8383 return shader ;
8484 }
8585
@@ -97,7 +97,7 @@ var webgl_pointFeature = function (arg) {
9797 function pointPolygon ( x , y , w , h ) {
9898 var verts ;
9999 switch ( m_primitiveShape ) {
100- case ' triangle' :
100+ case pointFeature . primitiveShapes . triangle :
101101 /* Use an equilateral triangle. While this has 30% more area than a
102102 * square, the reduction in vertices should help more than the
103103 * processing the additional fragments. */
@@ -107,11 +107,7 @@ var webgl_pointFeature = function (arg) {
107107 x + w * Math . sqrt ( 3.0 ) , y + h
108108 ] ;
109109 break ;
110- case 'sprite' :
111- /* Point sprite uses only one vertex per point. */
112- verts = [ x , y ] ;
113- break ;
114- default : // "square"
110+ case pointFeature . primitiveShapes . square :
115111 /* Use a surrounding square split diagonally into two triangles. */
116112 verts = [
117113 x - w , y + h ,
@@ -122,6 +118,10 @@ var webgl_pointFeature = function (arg) {
122118 x + w , y + h
123119 ] ;
124120 break ;
121+ default : // sprite
122+ /* Point sprite uses only one vertex per point. */
123+ verts = [ x , y ] ;
124+ break ;
125125 }
126126 return verts ;
127127 }
@@ -148,7 +148,7 @@ var webgl_pointFeature = function (arg) {
148148 fillColor , fillColorVal , fillColorFunc ,
149149 vpf = m_this . verticesPerFeature ( ) ,
150150 data = m_this . data ( ) ,
151- item , ivpf , ivpf3 , iunit , i3 ,
151+ item , ivpf , ivpf3 , iunit , i3 , maxr = 0 ,
152152 geom = m_mapper . geometryData ( ) ;
153153
154154 posFunc = m_this . position ( ) ;
@@ -185,9 +185,7 @@ var webgl_pointFeature = function (arg) {
185185
186186 posBuf = util . getGeomBuffer ( geom , 'pos' , vpf * numPts * 3 ) ;
187187
188- if ( m_primitiveShape !== 'sprite' ) {
189- unitBuf = util . getGeomBuffer ( geom , 'unit' , vpf * numPts * 2 ) ;
190- }
188+ unitBuf = util . getGeomBuffer ( geom , 'unit' , vpf * numPts * 2 ) ;
191189 indices = geom . primitive ( 0 ) . indices ( ) ;
192190 if ( ! ( indices instanceof Uint16Array ) || indices . length !== vpf * numPts ) {
193191 indices = new Uint16Array ( vpf * numPts ) ;
@@ -207,7 +205,7 @@ var webgl_pointFeature = function (arg) {
207205 for ( i = ivpf = ivpf3 = iunit = i3 = 0 ; i < numPts ; i += 1 , i3 += 3 ) {
208206 item = data [ i ] ;
209207 if ( ! onlyStyle ) {
210- if ( m_primitiveShape !== ' sprite' ) {
208+ if ( m_primitiveShape !== pointFeature . primitiveShapes . sprite ) {
211209 for ( j = 0 ; j < unit . length ; j += 1 , iunit += 1 ) {
212210 unitBuf [ iunit ] = unit [ j ] ;
213211 }
@@ -222,6 +220,11 @@ var webgl_pointFeature = function (arg) {
222220 fillVal = fillFunc ( item , i ) ? 1.0 : 0.0 ;
223221 fillOpacityVal = fillOpacityFunc ( item , i ) ;
224222 fillColorVal = fillColorFunc ( item , i ) ;
223+ if ( m_primitiveShapeAuto &&
224+ ( ( fillVal && fillOpacityVal ) || ( strokeVal && strokeOpacityVal ) ) &&
225+ radiusVal + ( strokeVal && strokeOpacityVal ? strokeWidthVal : 0 ) > maxr ) {
226+ maxr = radiusVal + ( strokeVal && strokeOpacityVal ? strokeWidthVal : 0 ) ;
227+ }
225228 for ( j = 0 ; j < vpf ; j += 1 , ivpf += 1 , ivpf3 += 3 ) {
226229 if ( ! onlyStyle ) {
227230 posBuf [ ivpf3 ] = position [ i3 ] ;
@@ -243,6 +246,18 @@ var webgl_pointFeature = function (arg) {
243246 }
244247 }
245248
249+ if ( m_primitiveShapeAuto &&
250+ ( ( m_primitiveShape === pointFeature . primitiveShapes . sprite && maxr > webglRenderer . _maxPointSize ) ||
251+ ( m_primitiveShape !== pointFeature . primitiveShapes . sprite && maxr <= webglRenderer . _maxPointSize ) ) ) {
252+ // Switch primitive
253+ m_primitiveShape = maxr > webglRenderer . _maxPointSize ? pointFeature . primitiveShapes . triangle : pointFeature . primitiveShapes . sprite ;
254+ m_this . renderer ( ) . contextRenderer ( ) . removeActor ( m_actor ) ;
255+ m_actor = null ;
256+ m_this . _init ( true ) ;
257+ createGLPoints ( ) ;
258+ return ;
259+ }
260+
246261 if ( ! onlyStyle ) {
247262 geom . boundsDirty ( true ) ;
248263 m_mapper . modified ( ) ;
@@ -379,10 +394,47 @@ var webgl_pointFeature = function (arg) {
379394 return m_this ;
380395 } ;
381396
397+ /**
398+ * Get or set the primitiveShape.
399+ *
400+ * @param {geo.pointFeature.primitiveShapes } [primitiveShape] If specified,
401+ * the new primitive shape.
402+ * @param {boolean } [currentShape] If truthy and getting the shape, return
403+ * the shape currently in use if the shape is set to `auto`. If falsy,
404+ * return the specifiec primitiveShape, which may be `auto`.
405+ * @returns {geo.pointFeature.primitiveShapes|this } The primitiveShape or
406+ * this instance of the feature.
407+ */
408+ this . primitiveShape = function ( primitiveShape , currentShape ) {
409+ if ( primitiveShape === undefined ) {
410+ return currentShape || ! m_primitiveShapeAuto ? m_primitiveShape : pointFeature . primitiveShapes . auto ;
411+ }
412+ if ( pointFeature . primitiveShapes [ primitiveShape ] !== undefined ) {
413+ var update = false ;
414+ if ( primitiveShape === pointFeature . primitiveShapes . auto ) {
415+ update = ! m_primitiveShapeAuto ;
416+ m_primitiveShapeAuto = true ;
417+ } else {
418+ update = m_primitiveShapeAuto || m_primitiveShape !== primitiveShape ;
419+ m_primitiveShapeAuto = false ;
420+ m_primitiveShape = primitiveShape ;
421+ }
422+ if ( update ) {
423+ m_this . renderer ( ) . contextRenderer ( ) . removeActor ( m_actor ) ;
424+ m_actor = null ;
425+ m_this . _init ( true ) ;
426+ m_this . modified ( ) ;
427+ }
428+ }
429+ return m_this ;
430+ } ;
431+
382432 /**
383433 * Initialize.
434+ *
435+ * @param {boolean } [reinit] If truthy, skip the parent class's init method.
384436 */
385- this . _init = function ( ) {
437+ this . _init = function ( reinit ) {
386438 var prog = vgl . shaderProgram ( ) ,
387439 vertexShader = createVertexShader ( ) ,
388440 fragmentShader = createFragmentShader ( ) ,
@@ -419,23 +471,27 @@ var webgl_pointFeature = function (arg) {
419471 1 , vgl . vertexAttributeKeysIndexed . Eight , { 'name' : 'fillOpacity' } ) ,
420472 sourceStrokeOpacity = vgl . sourceDataAnyfv (
421473 1 , vgl . vertexAttributeKeysIndexed . Nine , { 'name' : 'strokeOpacity' } ) ,
422- primitive = new vgl . triangles ( ) ;
474+ primitive ;
423475 m_modelViewUniform = new vgl . modelViewOriginUniform ( 'modelViewMatrix' , m_origin ) ;
424476
425- if ( m_primitiveShape === ' sprite' ) {
477+ if ( m_primitiveShape === pointFeature . primitiveShapes . sprite ) {
426478 primitive = new vgl . points ( ) ;
479+ } else {
480+ primitive = new vgl . triangles ( ) ;
427481 }
428482
429483 m_pixelWidthUniform = new vgl . floatUniform (
430484 'pixelWidth' , 2.0 / m_this . renderer ( ) . width ( ) ) ;
431485 m_aspectUniform = new vgl . floatUniform (
432486 'aspect' , m_this . renderer ( ) . width ( ) / m_this . renderer ( ) . height ( ) ) ;
433487
434- s_init . call ( m_this , arg ) ;
488+ if ( ! reinit ) {
489+ s_init . call ( m_this , arg ) ;
490+ }
435491 m_mapper = vgl . mapper ( { dynamicDraw : m_dynamicDraw } ) ;
436492
437493 prog . addVertexAttribute ( posAttr , vgl . vertexAttributeKeys . Position ) ;
438- if ( m_primitiveShape !== ' sprite' ) {
494+ if ( m_primitiveShape !== pointFeature . primitiveShapes . sprite ) {
439495 prog . addVertexAttribute ( unitAttr , vgl . vertexAttributeKeysIndexed . One ) ;
440496 }
441497
0 commit comments