1 /*************************************** 2 * Copyright 2011, 2012 GlobWeb contributors. 3 * 4 * This file is part of GlobWeb. 5 * 6 * GlobWeb is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU Lesser General Public License as published by 8 * the Free Software Foundation, version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * GlobWeb is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with GlobWeb. If not, see <http://www.gnu.org/licenses/>. 18 ***************************************/ 19 20 define( function() { 21 22 /**************************************************************************************************************/ 23 24 25 /** @constructor 26 * TiledVectorRenderable constructor 27 */ 28 var TiledVectorRenderable = function( bucket, gl ) 29 { 30 this.gl = gl; 31 this.bucket = bucket; 32 this.vertexBuffer = null; 33 this.indexBuffer = null; 34 this.vertices = []; 35 this.indices = []; 36 this.geometryInfos = []; 37 this.dirtyVB = true; 38 this.dirtyIB = true; 39 this.childrenIndexBuffers = null; 40 this.childrenIndices = null; 41 this.glMode = -1; 42 } 43 44 45 /**************************************************************************************************************/ 46 47 /** 48 * Build children indices. 49 * Children indices are used to render a tile children when it is not completely loaded. 50 */ 51 TiledVectorRenderable.prototype.buildChildrenIndices = function( ) 52 { 53 // Default method : nothing is done 54 this.childrenIndices = [ [], [], [], [] ]; 55 this.childrenIndexBuffers = [ null, null, null, null ]; 56 } 57 58 59 /**************************************************************************************************************/ 60 61 /** 62 * Remove a geometry from the renderable 63 */ 64 TiledVectorRenderable.prototype.removeGeometry = function( geometry ) 65 { 66 var fiIndex = -1; 67 68 // Find the feature 69 for ( var i = 0; i < this.geometryInfos.length; i++ ) 70 { 71 var fi = this.geometryInfos[i]; 72 if ( fi.geometry == geometry ) 73 { 74 // Remove feature from vertex and index buffer 75 this.vertices.splice( fi.startVertices, fi.vertexCount ); 76 this.indices.splice( fi.startIndices, fi.indexCount ); 77 78 // Update index buffer 79 var vertexOffset = fi.vertexCount / 3; 80 for ( var n = fi.startIndices; n < this.indices.length; n++ ) 81 { 82 this.indices[n] -= vertexOffset; 83 } 84 85 fiIndex = i; 86 87 break; 88 } 89 } 90 91 if ( fiIndex >= 0 ) 92 { 93 this.dirtyVB = true; 94 this.dirtyIB = true; 95 96 // Update feature infos 97 for ( var i = fiIndex + 1; i < this.geometryInfos.length; i++ ) 98 { 99 var fi = this.geometryInfos[i]; 100 fi.startVertices -= this.geometryInfos[fiIndex].vertexCount; 101 fi.startIndices -= this.geometryInfos[fiIndex].indexCount; 102 } 103 104 // Remove the feature from the infos array 105 this.geometryInfos.splice( fiIndex, 1 ); 106 107 // Erase children buffers : need to be rebuild 108 this.disposeChildrenIndexBuffers(); 109 this.childrenIndices = null; 110 111 return true; 112 } 113 else 114 { 115 return false; 116 } 117 } 118 119 /**************************************************************************************************************/ 120 121 /** 122 Check if a geometry crosses the date line 123 */ 124 TiledVectorRenderable.prototype._fixDateLine = function( tile, coords ) 125 { 126 var crossDateLine = false; 127 var startLon = coords[0][0]; 128 for ( var i = 1; i < coords.length && !crossDateLine; i++) { 129 var deltaLon = Math.abs( coords[i][0] - startLon ); 130 if ( deltaLon > 180 ) { 131 // DateLine! 132 crossDateLine = true; 133 } 134 } 135 136 if ( crossDateLine ) 137 { 138 var fixCoords = []; 139 140 if ( tile.geoBound.west < 0.0 ) 141 { 142 // Ensure coordinates are always negative 143 for ( var n = 0; n < coords.length; n++) { 144 if ( coords[n][0] > 0 ) { 145 fixCoords[n] = [ coords[n][0] - 360, coords[n][1] ]; 146 } else { 147 fixCoords[n] = [ coords[n][0], coords[n][1] ]; 148 } 149 } 150 } 151 else 152 { 153 // Ensure coordinates are always positive 154 for ( var n = 0; n < coords.length; n++) { 155 if ( coords[n][0] < 0 ) { 156 fixCoords[n] = [ coords[n][0] + 360, coords[n][1] ]; 157 } else { 158 fixCoords[n] = [ coords[n][0], coords[n][1] ]; 159 } 160 } 161 } 162 163 return fixCoords; 164 } 165 else 166 { 167 return coords; 168 } 169 }; 170 171 /**************************************************************************************************************/ 172 173 /** 174 * Add a feature to the renderable 175 */ 176 TiledVectorRenderable.prototype.addGeometry = function( geometry, tile ) 177 { 178 var geometryInfo = { geometry: geometry, 179 startVertices: this.vertices.length, 180 startIndices: this.indices.length, 181 vertexCount: 0, 182 indexCount: 0 }; 183 184 var coords = geometry['coordinates']; 185 switch (geometry['type']) 186 { 187 case "LineString": 188 this.buildVerticesAndIndices( tile, coords ); 189 break; 190 case "Polygon": 191 for ( var i = 0; i < coords.length; i++ ) 192 this.buildVerticesAndIndices( tile, coords[i] ); 193 break; 194 case "MultiLineString": 195 for ( var i = 0; i < coords.length; i++ ) 196 this.buildVerticesAndIndices( tile, coords[i] ); 197 break; 198 case "MultiPolygon": 199 for ( var j = 0; j < coords.length; j++ ) 200 for ( var i = 0; i < coords[j].length; i++ ) 201 this.buildVerticesAndIndices( tile, coords[j][i] ); 202 break; 203 } 204 205 geometryInfo.vertexCount = this.vertices.length - geometryInfo.startVertices; 206 geometryInfo.indexCount = this.indices.length - geometryInfo.startIndices; 207 208 if ( geometryInfo.vertexCount > 0 ) 209 { 210 this.geometryInfos.push( geometryInfo ); 211 this.dirtyVB = true; 212 this.dirtyIB = true; 213 214 // Erase children buffers : need to be rebuild 215 this.disposeChildrenIndexBuffers(); 216 this.childrenIndices = null; 217 218 return true; 219 } 220 else 221 { 222 // Feature not in the tile 223 return false; 224 } 225 } 226 227 /**************************************************************************************************************/ 228 229 /** 230 * Dispose children index buffers 231 */ 232 TiledVectorRenderable.prototype.disposeChildrenIndexBuffers = function() 233 { 234 var gl = this.gl; 235 236 if ( this.childrenIndexBuffers ) 237 { 238 if ( this.childrenIndexBuffers[0] ) 239 gl.deleteBuffer(this.childrenIndexBuffers[0]); 240 if ( this.childrenIndexBuffers[1] ) 241 gl.deleteBuffer(this.childrenIndexBuffers[1]); 242 if ( this.childrenIndexBuffers[2] ) 243 gl.deleteBuffer(this.childrenIndexBuffers[2]); 244 if ( this.childrenIndexBuffers[3] ) 245 gl.deleteBuffer(this.childrenIndexBuffers[3]); 246 } 247 248 this.childrenIndexBuffers = null; 249 } 250 251 /**************************************************************************************************************/ 252 253 /** 254 * Dispose graphics data 255 */ 256 TiledVectorRenderable.prototype.dispose = function() 257 { 258 var gl = this.gl; 259 260 if ( this.indexBuffer ) 261 gl.deleteBuffer(this.indexBuffer); 262 if ( this.vertexBuffer ) 263 gl.deleteBuffer(this.vertexBuffer); 264 265 this.disposeChildrenIndexBuffers(); 266 267 this.indexBuffer = null; 268 this.vertexBuffer = null; 269 } 270 271 /**************************************************************************************************************/ 272 273 /** 274 * Render the line string for a child tile 275 * Used for loading tiles 276 */ 277 TiledVectorRenderable.prototype.renderChild = function(attributes, childIndex) 278 { 279 if ( this.childrenIndices == null ) 280 this.buildChildrenIndices(); 281 282 var childIndices = this.childrenIndices[childIndex]; 283 if ( childIndices.length == 0 ) 284 return; 285 286 var gl = this.gl; 287 288 // Bind and update VertexBuffer 289 if ( this.vertexBuffer == null ) 290 this.vertexBuffer = gl.createBuffer(); 291 gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); 292 if ( this.dirtyVB ) 293 { 294 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.vertices), gl.STATIC_DRAW); 295 this.dirtyVB = false; 296 } 297 298 // Warning : use quoted strings to access properties of the attributes, to work correclty in advanced mode with closure compiler 299 gl.vertexAttribPointer(attributes['vertex'], 3, gl.FLOAT, false, 0, 0); 300 301 // Bind IndexBuffer 302 var ib = this.childrenIndexBuffers[childIndex]; 303 if ( !ib ) 304 { 305 var gl = this.gl; 306 ib = gl.createBuffer(); 307 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ib); 308 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(childIndices), gl.STATIC_DRAW); 309 this.childrenIndexBuffers[childIndex] = ib; 310 } 311 else 312 { 313 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,ib); 314 } 315 316 317 gl.drawElements( this.glMode, childIndices.length, gl.UNSIGNED_SHORT, 0); 318 } 319 320 /**************************************************************************************************************/ 321 322 /** 323 * Render the line string 324 */ 325 TiledVectorRenderable.prototype.render = function(attributes) 326 { 327 var gl = this.gl; 328 329 // Bind and update VertexBuffer 330 if ( this.vertexBuffer == null ) 331 this.vertexBuffer = gl.createBuffer(); 332 gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); 333 if ( this.dirtyVB ) 334 { 335 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.vertices), gl.STATIC_DRAW); 336 this.dirtyVB = false; 337 } 338 339 // Warning : use quoted strings to access properties of the attributes, to work correclty in advanced mode with closure compiler 340 gl.vertexAttribPointer(attributes['vertex'], 3, gl.FLOAT, false, 0, 0); 341 342 // Bind and update IndexBuffer 343 if ( this.indexBuffer == null ) 344 this.indexBuffer = gl.createBuffer(); 345 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); 346 if ( this.dirtyIB ) 347 { 348 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(this.indices), gl.STATIC_DRAW); 349 this.dirtyIB = false; 350 } 351 352 gl.drawElements( this.glMode, this.indices.length, gl.UNSIGNED_SHORT, 0); 353 } 354 355 /**************************************************************************************************************/ 356 357 return TiledVectorRenderable; 358 359 }); 360