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(['./Utils', './BaseLayer','./Program','./Tile'], 
 21 	function(Utils, BaseLayer, Program, Tile) {
 22 
 23 /**************************************************************************************************************/
 24 
 25 /** 
 26 	@constructor
 27 	Function constructor for TileWireframeLayer
 28  */
 29 var TileWireframeLayer = function( options )
 30 {
 31 	BaseLayer.prototype.constructor.call( this, options );
 32 	this.outline = (options && options['outline']) ? options['outline'] : false;
 33 	this.globe = null;
 34 	this.program = null;
 35 	this.indexBuffer = null;
 36 	this.subIndexBuffer = [ null, null, null, null ];
 37 }
 38 
 39 /**************************************************************************************************************/
 40 
 41 Utils.inherits( BaseLayer,TileWireframeLayer );
 42 
 43 /**************************************************************************************************************/
 44 
 45 /** 
 46   Build the index buffer
 47  */
 48 TileWireframeLayer.prototype.buildIndexBuffer = function()
 49 {
 50 	var gl = this.globe.renderContext.gl;
 51 	var size = this.globe.tileManager.tileConfig.tesselation;
 52 	var indices = [];
 53 	
 54 	var step = this.outline ? size-1 : 1;
 55 	
 56 	// Build horizontal lines
 57 	for ( var j=0; j < size; j += step)
 58 	{
 59 		for ( var i=0; i < size-1; i++)
 60 		{
 61 			indices.push( j * size + i );
 62 			indices.push( j * size + i + 1 );
 63 		}
 64 	}
 65 
 66 	// Build vertical lines
 67 	for ( var j=0; j < size; j += step)
 68 	{
 69 		for ( var i=0; i < size-1; i++)
 70 		{
 71 			indices.push( i * size + j );
 72 			indices.push( (i+1) * size + j );
 73 		}
 74 	}
 75 
 76 	
 77 	var ib = gl.createBuffer();
 78 	gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ib);
 79 	gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
 80 	
 81 	ib.numIndices = indices.length;
 82 	this.indexBuffer = ib;
 83 	
 84 	var halfTesselation = (size-1) / 2;
 85 	step = this.outline ? halfTesselation : 1;
 86 	for ( var ii = 0; ii < 4; ii++ )
 87 	{
 88 		var i = ii % 2;
 89 		var j = Math.floor( ii / 2 );
 90 		
 91 		// Build the sub grid for 'inside' tile
 92 		var indices = [];
 93 		for ( var n=halfTesselation*j; n < halfTesselation*(j+1)+1; n+= step)
 94 		{
 95 			for ( var k=halfTesselation*i; k < halfTesselation*(i+1); k++)
 96 			{
 97 				indices.push( n * size + k );
 98 				indices.push( n * size + k + 1 );
 99 			}
100 		}
101 		for ( var n=halfTesselation*i; n < halfTesselation*(i+1)+1; n+= step)
102 		{
103 			for ( var k=halfTesselation*j; k < halfTesselation*(j+1); k++)
104 			{
105 				indices.push( k * size + n );
106 				indices.push( (k+1) * size + n );
107 			}
108 		}
109 	
110 		var ib = gl.createBuffer();
111 		gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ib);
112 		gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
113 		ib.numIndices = indices.length;
114 		this.subIndexBuffer[ii] = ib;
115 	}
116 }
117 
118 /**************************************************************************************************************/
119 
120 /** 
121   Attach the layer to the globe
122  */
123 TileWireframeLayer.prototype._attach = function( g )
124 {
125 	BaseLayer.prototype._attach.call( this, g );
126 	
127 	if ( this._visible )
128 	{
129 		this.globe.tileManager.addPostRenderer(this);
130 	}
131 	
132 	if (!this.program)
133 	{
134 		var vertexShader = "\
135 		attribute vec3 vertex;\n\
136 		uniform mat4 modelViewMatrix;\n\
137 		uniform mat4 projectionMatrix;\n\
138 		void main(void) \n\
139 		{\n\
140 			gl_Position = projectionMatrix * modelViewMatrix * vec4(vertex, 1.0);\n\
141 		}\n\
142 		";
143 
144 		var fragmentShader = "\
145 		precision highp float; \n\
146 		uniform float alpha; \n\
147 		void main(void)\n\
148 		{\n\
149 				gl_FragColor = vec4(1.0,1.0,1.0,alpha);\n\
150 		}\n\
151 		";
152 		
153 		this.program = new Program(this.globe.renderContext);
154 		this.program.createFromSource( vertexShader, fragmentShader );
155 		
156 		this.buildIndexBuffer();
157 	}
158 }
159 
160 /**************************************************************************************************************/
161 
162 /** 
163   Detach the layer from the globe
164  */
165 TileWireframeLayer.prototype._detach = function()
166 {
167 	this.globe.tileManager.removePostRenderer(this);
168 	BaseLayer.prototype._detach.call(this);
169 }
170 
171 /**************************************************************************************************************/
172 
173 /**
174 	Render the tiles outline
175  */
176 TileWireframeLayer.prototype.render = function( tiles )
177 {
178 	var rc = this.globe.renderContext;
179 	var gl = rc.gl;
180 	
181 	gl.enable(gl.BLEND);
182 	
183 	// Setup program
184 	this.program.apply();
185 	gl.uniformMatrix4fv(this.program.uniforms["projectionMatrix"], false, rc.projectionMatrix);
186 	
187 	var vertexAttribute = this.program.attributes['vertex'];
188 	var currentIB = null;	
189 	
190 	for ( var i = 0; i < tiles.length; i++ )
191 	{
192 		var tile = tiles[i];
193 		
194 		var isLoaded = ( tile.state == Tile.State.LOADED );
195 		var isLevelZero = ( tile.parentIndex == -1 );
196 	
197 		// Update uniforms for modelview matrix
198 		mat4.multiply( rc.viewMatrix, tile.matrix, rc.modelViewMatrix );
199 		gl.uniformMatrix4fv(this.program.uniforms["modelViewMatrix"], false, rc.modelViewMatrix);
200 		gl.uniform1f(this.program.uniforms["alpha"], this.opacity() );
201 			
202 		// Bind the vertex buffer
203 		gl.bindBuffer(gl.ARRAY_BUFFER, tile.vertexBuffer);
204 		gl.vertexAttribPointer(vertexAttribute, 3, gl.FLOAT, false, 4*tile.config.vertexSize, 0);
205 		
206 		var indexBuffer = ( isLoaded || isLevelZero ) ? this.indexBuffer : this.subIndexBuffer[tile.parentIndex];
207 		// Bind the index buffer only if different (index buffer is shared between tiles)
208 		if ( currentIB != indexBuffer )
209 		{
210 			gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
211 			currentIB = indexBuffer;
212 		}
213 		
214 		// Draw the tiles in wireframe mode
215 		var numIndices = currentIB.numIndices;
216 		gl.drawElements(gl.LINES, currentIB.numIndices, gl.UNSIGNED_SHORT, 0);
217 	}
218 	
219 	gl.disable(gl.BLEND);
220 }
221 
222 /**************************************************************************************************************/
223 
224 /**
225  * 	Set visibility of the layer
226  */
227 TileWireframeLayer.prototype.visible = function( arg )
228 {
229 	if ( typeof arg == "boolean" && this._visible != arg )
230 	{
231 		this._visible = arg;
232 		
233 		if ( arg ){
234 			this.globe.tileManager.addPostRenderer(this);
235 		}
236 		else
237 		{
238 			this.globe.tileManager.removePostRenderer(this);
239 		}
240 	}
241 	
242 	return this._visible;
243 }
244 
245 return TileWireframeLayer;
246 
247 });
248