libtess.js test on medium large polygon, more info here
Last active
August 29, 2015 14:04
-
-
Save Sumbera/01cbd44a77b4283e6dcd to your computer and use it in GitHub Desktop.
Polygon libtess fill in WebGL
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<title>Polygon libtess fill in WebGL</title> | |
<meta charset="utf-8"> | |
<style> | |
html, body { | |
height: 100%; | |
padding: 0; | |
margin: 0; | |
background: rgb(14, 21, 30); | |
height: 100%; | |
} | |
#map { | |
position: absolute; | |
height: 100%; | |
width: 100%; | |
background-color: #333; | |
} | |
</style> | |
<!-- vertex shader --> | |
<script id="vshader" type="x-shader/x-vertex"> | |
uniform mat4 u_matrix; | |
attribute vec4 a_vertex; | |
attribute float a_pointSize; | |
attribute vec4 a_color; | |
varying vec4 v_color; | |
void main() { | |
// Set the size of the point | |
gl_PointSize = a_pointSize; | |
// multiply each vertex by a matrix. | |
gl_Position = u_matrix * a_vertex; | |
// pass the color to the fragment shader | |
v_color = a_color; | |
} | |
</script> | |
<!-- fragment shader --> | |
<script id="fshader" type="x-shader/x-fragment"> | |
precision mediump float; | |
varying vec4 v_color; | |
void main() { | |
// -- squares | |
gl_FragColor = v_color; //vec4(0.8, 0.1,0.1, 0.9); //v_color; | |
gl_FragColor.a = 0.8; | |
} | |
</script> | |
<script src="http://www.sumbera.com/gist/js/libtess/libtess.cat.js"></script> | |
<script> | |
/*global libtess */ | |
var tessy = (function initTesselator() { | |
// function called for each vertex of tesselator output | |
function vertexCallback(data, polyVertArray) { | |
// console.log(data[0], data[1]); | |
polyVertArray[polyVertArray.length] = data[0]; | |
polyVertArray[polyVertArray.length] = data[1]; | |
polyVertArray[polyVertArray.length] = currentColor[0]; | |
polyVertArray[polyVertArray.length] = currentColor[1]; | |
polyVertArray[polyVertArray.length] = currentColor[2]; | |
} | |
function begincallback(type) { | |
if (type !== libtess.primitiveType.GL_TRIANGLES) { | |
console.log('expected TRIANGLES but got type: ' + type); | |
} | |
} | |
function errorcallback(errno) { | |
console.log('error callback'); | |
console.log('error number: ' + errno); | |
} | |
// callback for when segments intersect and must be split | |
function combinecallback(coords, data, weight) { | |
// console.log('combine callback'); | |
return [coords[0], coords[1], coords[2]]; | |
} | |
function edgeCallback(flag) { | |
// don't really care about the flag, but need no-strip/no-fan behavior | |
// console.log('edge flag: ' + flag); | |
} | |
var tessy = new libtess.GluTesselator(); | |
// tessy.gluTessProperty(libtess.gluEnum.GLU_TESS_WINDING_RULE, libtess.windingRule.GLU_TESS_WINDING_POSITIVE); | |
tessy.gluTessCallback(libtess.gluEnum.GLU_TESS_VERTEX_DATA, vertexCallback); | |
tessy.gluTessCallback(libtess.gluEnum.GLU_TESS_BEGIN, begincallback); | |
tessy.gluTessCallback(libtess.gluEnum.GLU_TESS_ERROR, errorcallback); | |
tessy.gluTessCallback(libtess.gluEnum.GLU_TESS_COMBINE, combinecallback); | |
tessy.gluTessCallback(libtess.gluEnum.GLU_TESS_EDGE_FLAG, edgeCallback); | |
return tessy; | |
})(); | |
</script> | |
</head> | |
<body> | |
<div id="map" ></div> | |
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css" /> | |
<script src="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js"></script> | |
<script src="http://www.sumbera.com/gist/js/leaflet/canvas/L.CanvasOverlay.js"></script> | |
<script src="http://www.sumbera.com/gist/data/CZDistricts.js" charset="utf-8"></script> | |
<script> | |
var leafletMap = L.map('map').setView([50.00, 14.44], 8); | |
L.tileLayer("http://{s}.sm.mapstack.stamen.com/(toner-background,$fff[difference],$fff[@23],$fff[hsl-saturation@20],toner-lines[destination-in])/{z}/{x}/{y}.png") | |
//L.tileLayer("http://{s}.sm.mapstack.stamen.com/(toner-lite,$fff[difference],$fff[@23],$fff[hsl-saturation@20])/{z}/{x}/{y}.png") | |
.addTo(leafletMap); | |
var glLayer = L.canvasOverlay() | |
.drawing(drawingOnCanvas) | |
.addTo(leafletMap); | |
var canvas = glLayer.canvas(); | |
glLayer.canvas.width = canvas.clientWidth; | |
glLayer.canvas.height = canvas.clientHeight; | |
var gl = canvas.getContext('experimental-webgl', { antialias: true }); | |
var pixelsToWebGLMatrix = new Float32Array(16); | |
var mapMatrix = new Float32Array(16); | |
// -- WebGl setup | |
var vertexShader = gl.createShader(gl.VERTEX_SHADER); | |
gl.shaderSource(vertexShader, document.getElementById('vshader').text); | |
gl.compileShader(vertexShader); | |
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); | |
gl.shaderSource(fragmentShader, document.getElementById('fshader').text); | |
gl.compileShader(fragmentShader); | |
// link shaders to create our program | |
var program = gl.createProgram(); | |
gl.attachShader(program, vertexShader); | |
gl.attachShader(program, fragmentShader); | |
gl.linkProgram(program); | |
gl.useProgram(program); | |
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); | |
gl.enable(gl.BLEND); | |
// gl.disable(gl.DEPTH_TEST); | |
// ---------------------------- | |
// look up the locations for the inputs to our shaders. | |
var u_matLoc = gl.getUniformLocation(program, "u_matrix"); | |
gl.aPointSize = gl.getAttribLocation(program, "a_pointSize"); | |
// Set the matrix to some that makes 1 unit 1 pixel. | |
pixelsToWebGLMatrix.set([2 / canvas.width, 0, 0, 0, 0, -2 / canvas.height, 0, 0, 0, 0, 0, 0, -1, 1, 0, 1]); | |
gl.viewport(0, 0, canvas.width, canvas.height); | |
gl.uniformMatrix4fv(u_matLoc, false, pixelsToWebGLMatrix); | |
var currentColor; | |
// -- data | |
var verts = []; | |
//-- verts only | |
/* | |
data.features[0].geometry.coordinates[0].map(function (d, i) { | |
pixel = LatLongToPixelXY(d[1], d[0]); | |
verts.push(pixel.x, pixel.y, 0.1, 0.6, 0.1); | |
}); | |
*/ | |
var start = new Date(); | |
var all = []; | |
var numfeatures = data.features.length; | |
data.features.map(function (b, i) { | |
tessy.gluTessNormal(0, 0, 1); | |
tessy.gluTessBeginPolygon(verts); | |
tessy.gluTessBeginContour(); | |
currentColor = [Math.random(), Math.random(), Math.random()]; //[0.1, 0.6, 0.1]; | |
b.geometry.coordinates[0].map(function (d, i) { | |
pixel = LatLongToPixelXY(d[1], d[0],0); | |
var coords = [pixel.x, pixel.y, 0]; | |
tessy.gluTessVertex(coords, coords); | |
}); | |
tessy.gluTessEndContour(); | |
tessy.gluTessEndPolygon(); | |
all = verts.concat(all); | |
verts = []; | |
}); | |
verts = all; | |
console.log("updated at " + new Date().setTime(new Date().getTime() - start.getTime()) + " ms "); | |
// tirangles or point count | |
var numPoints = verts.length / 5; | |
console.log("num points: " + numPoints); | |
var vertBuffer = gl.createBuffer(); | |
var vertArray = new Float32Array(verts); | |
var fsize = vertArray.BYTES_PER_ELEMENT; | |
gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer); | |
gl.bufferData(gl.ARRAY_BUFFER, vertArray, gl.STATIC_DRAW); | |
var vertLoc = gl.getAttribLocation(program, "a_vertex"); | |
gl.vertexAttribPointer(vertLoc, 2, gl.FLOAT, false, fsize * 5, 0); | |
gl.enableVertexAttribArray(vertLoc); | |
// -- offset for color buffer | |
var colorLoc = gl.getAttribLocation(program, "a_color"); | |
gl.vertexAttribPointer(colorLoc, 3, gl.FLOAT, false, fsize * 5, fsize * 2); | |
gl.enableVertexAttribArray(colorLoc); | |
glLayer.redraw(); | |
function drawingOnCanvas(canvasOverlay, params) { | |
if (gl == null) return; | |
gl.clear(gl.COLOR_BUFFER_BIT); | |
pixelsToWebGLMatrix.set([2 / canvas.width, 0, 0, 0, 0, -2 / canvas.height, 0, 0, 0, 0, 0, 0, -1, 1, 0, 1]); | |
gl.viewport(0, 0, canvas.width, canvas.height); | |
var pointSize = Math.max(leafletMap.getZoom() - 4.0, 1.0); | |
gl.vertexAttrib1f(gl.aPointSize, pointSize); | |
// -- set base matrix to translate canvas pixel coordinates -> webgl coordinates | |
mapMatrix.set(pixelsToWebGLMatrix); | |
var bounds = leafletMap.getBounds(); | |
var topLeft = new L.LatLng(bounds.getNorth(), bounds.getWest()); | |
var offset = LatLongToPixelXY(topLeft.lat, topLeft.lng); | |
// -- Scale to current zoom | |
var scale = Math.pow(2, leafletMap.getZoom()); | |
scaleMatrix(mapMatrix, scale, scale); | |
translateMatrix(mapMatrix, -offset.x, -offset.y); | |
// -- attach matrix value to 'mapMatrix' uniform in shader | |
gl.uniformMatrix4fv(u_matLoc, false, mapMatrix); | |
gl.drawArrays(gl.TRIANGLES, 0, numPoints); | |
} | |
// Returns a random integer from 0 to range - 1. | |
function randomInt(range) { | |
return Math.floor(Math.random() * range); | |
} | |
/* | |
function latlonToPixels(lat, lon) { | |
initialResolution = 2 * Math.PI * 6378137 / 256, // at zoomlevel 0 | |
originShift = 2 * Math.PI * 6378137 / 2; | |
// -- to meters | |
var mx = lon * originShift / 180; | |
var my = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180); | |
my = my * originShift / 180; | |
// -- to pixels at zoom level 0 | |
var res = initialResolution; | |
x = (mx + originShift) / res, | |
y = (my + originShift) / res; | |
return { x: x, y: 256- y }; | |
} | |
*/ | |
// -- converts latlon to pixels at zoom level 0 (for 256x256 tile size) , inverts y coord ) | |
// -- source : http://build-failed.blogspot.cz/2013/02/displaying-webgl-data-on-google-maps.html | |
function LatLongToPixelXY(latitude, longitude) { | |
var pi_180 = Math.PI / 180.0; | |
var pi_4 = Math.PI * 4; | |
var sinLatitude = Math.sin(latitude * pi_180); | |
var pixelY = (0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / (pi_4)) * 256; | |
var pixelX = ((longitude + 180) / 360) * 256; | |
var pixel = { x: pixelX, y: pixelY }; | |
return pixel; | |
} | |
function translateMatrix(matrix, tx, ty) { | |
// translation is in last column of matrix | |
matrix[12] += matrix[0] * tx + matrix[4] * ty; | |
matrix[13] += matrix[1] * tx + matrix[5] * ty; | |
matrix[14] += matrix[2] * tx + matrix[6] * ty; | |
matrix[15] += matrix[3] * tx + matrix[7] * ty; | |
} | |
function scaleMatrix(matrix, scaleX, scaleY) { | |
// scaling x and y, which is just scaling first two columns of matrix | |
matrix[0] *= scaleX; | |
matrix[1] *= scaleX; | |
matrix[2] *= scaleX; | |
matrix[3] *= scaleX; | |
matrix[4] *= scaleY; | |
matrix[5] *= scaleY; | |
matrix[6] *= scaleY; | |
matrix[7] *= scaleY; | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment