From 5c8e5d10cb5c24874ff44cecfcce48c5efb3e9e0 Mon Sep 17 00:00:00 2001 From: Matthew Amato Date: Wed, 4 Mar 2015 11:57:46 -0500 Subject: [PATCH 1/8] Font kerning support for LabelCollection `writeTextToCanvas` now always draws individual letters more reliably and keeps them completely in the canvas. `LabelCollection` now uses the `dimensions` object returned by `writeTextToCanvas` to perform accurate kerning, producing much more legible and visually appealing text. --- CHANGES.md | 1 + Source/Core/writeTextToCanvas.js | 26 +++++++++++++++++++------- Source/Scene/LabelCollection.js | 15 +++++++++++++-- Specs/Core/writeTextToCanvasSpec.js | 10 ++++++---- 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 4acf539447a6..10549901661a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,7 @@ Change Log * * Deprecated * +* Added font kerning support to labels, improving visual quality and legibility. * Improved KML compatibility to work with non-specification compliant KML files that still happen to load in Google Earth. * Fixed a crash when loading KML features that have no description and an empty `ExtendedData` node. * Added support for KML `TimeStamp` nodes. diff --git a/Source/Core/writeTextToCanvas.js b/Source/Core/writeTextToCanvas.js index 6178d708075b..5ff707ea566b 100644 --- a/Source/Core/writeTextToCanvas.js +++ b/Source/Core/writeTextToCanvas.js @@ -82,16 +82,28 @@ define([ document.body.appendChild(canvas); var dimensions = measureText(context2D, text, stroke, fill); - dimensions.computedWidth = Math.max(dimensions.width, dimensions.bounds.maxx - dimensions.bounds.minx); canvas.dimensions = dimensions; document.body.removeChild(canvas); canvas.style.visibility = ''; - var baseline = dimensions.height - dimensions.ascent; - canvas.width = dimensions.computedWidth; - canvas.height = dimensions.height; - var y = canvas.height - baseline; + //Some characters, such as the letter j, have a non-zero starting position. + //This value is used for kering later, but we need to take it into account + //now in order to draw the text completely on the canvas + var x = -dimensions.bounds.minx; + + //Expand the width to include the starting position. + var width = Math.ceil(dimensions.width) + x; + + //While the height of the letter is correct, we need to adjust + //where we start drawing it so that letters like j and y properly dip + //below the line. + var height = dimensions.height; + var baseline = height - dimensions.ascent; + var y = height - baseline; + + canvas.width = width; + canvas.height = height; // Properties must be explicitly set again after changing width and height context2D.font = font; @@ -102,13 +114,13 @@ define([ if (stroke) { var strokeColor = defaultValue(options.strokeColor, Color.BLACK); context2D.strokeStyle = strokeColor.toCssColorString(); - context2D.strokeText(text, 0, y); + context2D.strokeText(text, x, y); } if (fill) { var fillColor = defaultValue(options.fillColor, Color.WHITE); context2D.fillStyle = fillColor.toCssColorString(); - context2D.fillText(text, 0, y); + context2D.fillText(text, x, y); } return canvas; diff --git a/Source/Scene/LabelCollection.js b/Source/Scene/LabelCollection.js index 287bb0398801..f071da62a2c0 100644 --- a/Source/Scene/LabelCollection.js +++ b/Source/Scene/LabelCollection.js @@ -223,8 +223,13 @@ define([ for (glyphIndex = 0; glyphIndex < glyphLength; ++glyphIndex) { glyph = glyphs[glyphIndex]; dimensions = glyph.dimensions; - totalWidth += dimensions.computedWidth; maxHeight = Math.max(maxHeight, dimensions.height); + + //Computing the total width must also account for the kering that occurs between letters. + totalWidth += dimensions.width - dimensions.bounds.minx; + if (glyphIndex < glyphLength - 1) { + totalWidth += glyphs[glyphIndex + 1].dimensions.bounds.minx; + } } var scale = label._scale; @@ -258,7 +263,13 @@ define([ glyph.billboard._setTranslate(glyphPixelOffset); } - glyphPixelOffset.x += dimensions.computedWidth * scale * resolutionScale; + //Compute the next x offset taking into acocunt the kerning performed + //on both the current letter as well as the next letter to be drawn + //as well as any applied scale. + if (glyphIndex < glyphLength - 1) { + var nextGlyph = glyphs[glyphIndex + 1]; + glyphPixelOffset.x += ((dimensions.width - dimensions.bounds.minx) + nextGlyph.dimensions.bounds.minx) * scale * resolutionScale; + } } } diff --git a/Specs/Core/writeTextToCanvasSpec.js b/Specs/Core/writeTextToCanvasSpec.js index b8ddf14e0a59..c6c11313b559 100644 --- a/Specs/Core/writeTextToCanvasSpec.js +++ b/Specs/Core/writeTextToCanvasSpec.js @@ -81,8 +81,10 @@ defineSuite([ stroke : false }); - // canvas1 is filled, so there should only be two "edges" - expect(getColorChangeCount(canvas1)).toEqual(2); + // canvas1 is filled, completely by the I on the left + // and then has empty space on the right, so there + // should only be one "edge": fill -> outside + expect(getColorChangeCount(canvas1)).toEqual(1); var canvas2 = writeTextToCanvas('I', { font : '90px "Open Sans"', @@ -91,7 +93,7 @@ defineSuite([ strokeColor : Color.BLUE }); - // canvas2 is stroked, so there should be four "edges" - expect(getColorChangeCount(canvas2)).toEqual(4); + // canvas2 is stroked, so there should be three "edges": outline -> inside -> outline -> outside + expect(getColorChangeCount(canvas2)).toEqual(3); }); }); \ No newline at end of file From 3550a1fa150dddd2e47040835f80e339efe27cd8 Mon Sep 17 00:00:00 2001 From: Ed Mackey Date: Tue, 22 Nov 2016 12:07:56 -0500 Subject: [PATCH 2/8] Billboard halfsize must be computed after compressedAttributes. Compressed vertex attributes must be integers. Billboard halfSize is needed for computing the distance from the center of the billboard out to one of the corners. But the half-size can have a .5 fractional component, from the least significant bit of the original billboard size. So this 0.5 must be computed after the compressed vertex attribute has already been unpacked. --- Source/Scene/BillboardCollection.js | 4 ++-- Source/Shaders/BillboardCollectionVS.glsl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Scene/BillboardCollection.js b/Source/Scene/BillboardCollection.js index 78836da2f652..6a09335c9654 100644 --- a/Source/Scene/BillboardCollection.js +++ b/Source/Scene/BillboardCollection.js @@ -915,7 +915,7 @@ define([ } var textureWidth = billboardCollection._textureAtlas.texture.width; - var imageWidth = Math.ceil(defaultValue(billboard.width, textureWidth * width) * 0.5); + var imageWidth = Math.round(defaultValue(billboard.width, textureWidth * width)); billboardCollection._maxSize = Math.max(billboardCollection._maxSize, imageWidth); var compressed0 = CesiumMath.clamp(imageWidth, 0.0, LEFT_SHIFT16); @@ -970,7 +970,7 @@ define([ } var dimensions = billboardCollection._textureAtlas.texture.dimensions; - var imageHeight = Math.ceil(defaultValue(billboard.height, dimensions.y * height) * 0.5); + var imageHeight = Math.round(defaultValue(billboard.height, dimensions.y * height)); billboardCollection._maxSize = Math.max(billboardCollection._maxSize, imageHeight); var red = Color.floatToByte(color.red); diff --git a/Source/Shaders/BillboardCollectionVS.glsl b/Source/Shaders/BillboardCollectionVS.glsl index 232661ddb6eb..3469a2165be4 100644 --- a/Source/Shaders/BillboardCollectionVS.glsl +++ b/Source/Shaders/BillboardCollectionVS.glsl @@ -38,7 +38,7 @@ const float SHIFT_RIGHT1 = 1.0 / 2.0; vec4 computePositionWindowCoordinates(vec4 positionEC, vec2 imageSize, float scale, vec2 direction, vec2 origin, vec2 translate, vec2 pixelOffset, vec3 alignedAxis, bool validAlignedAxis, float rotation, bool sizeInMeters) { - vec2 halfSize = imageSize * scale * czm_resolutionScale; + vec2 halfSize = imageSize * scale * czm_resolutionScale * 0.5; halfSize *= ((direction * 2.0) - 1.0); vec2 originTranslate = origin * abs(halfSize); From 79a196297c357520ecee6c8f791a10826f893af2 Mon Sep 17 00:00:00 2001 From: Ed Mackey Date: Mon, 21 Nov 2016 13:09:00 -0500 Subject: [PATCH 3/8] Change Billboard depth function from LESS to LEQUAL. --- CHANGES.md | 1 + Source/Scene/BillboardCollection.js | 5 ++++- Source/Scene/PointPrimitiveCollection.js | 5 ++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index b6b5b82dd5a3..c7beedadb6b5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,7 @@ Change Log * Breaking changes * * Improved terrain/imagery load ordering, especially when the terrain is already fully loaded and we add a new imagery layer. This results in a 25% reduction in load times in many cases. +* Billboard depth testing changed from `LESS` to `LEQUAL`, allowing label glyphs of equal depths to overlap. * Added support for saving html and css in Github Gists. [#4125](https://github.com/AnalyticalGraphicsInc/cesium/issues/4125) * Fixed `Cartographic.fromCartesian` when the cartesian is not on the ellipsoid surface. [#4611](https://github.com/AnalyticalGraphicsInc/cesium/issues/4611) diff --git a/Source/Scene/BillboardCollection.js b/Source/Scene/BillboardCollection.js index 6a09335c9654..34370f8819de 100644 --- a/Source/Scene/BillboardCollection.js +++ b/Source/Scene/BillboardCollection.js @@ -22,6 +22,7 @@ define([ '../Renderer/ShaderProgram', '../Renderer/ShaderSource', '../Renderer/VertexArrayFacade', + '../Renderer/WebGLConstants', '../Shaders/BillboardCollectionFS', '../Shaders/BillboardCollectionVS', './Billboard', @@ -55,6 +56,7 @@ define([ ShaderProgram, ShaderSource, VertexArrayFacade, + WebGLConstants, BillboardCollectionFS, BillboardCollectionVS, Billboard, @@ -1424,7 +1426,8 @@ define([ if (!defined(this._rs)) { this._rs = RenderState.fromCache({ depthTest : { - enabled : true + enabled : true, + func : WebGLConstants.LEQUAL // Allows label glyphs and billboards to overlap. }, blending : BlendingState.ALPHA_BLEND }); diff --git a/Source/Scene/PointPrimitiveCollection.js b/Source/Scene/PointPrimitiveCollection.js index 1d4a241b7dc4..e241049c4b3c 100644 --- a/Source/Scene/PointPrimitiveCollection.js +++ b/Source/Scene/PointPrimitiveCollection.js @@ -21,6 +21,7 @@ define([ '../Renderer/ShaderProgram', '../Renderer/ShaderSource', '../Renderer/VertexArrayFacade', + '../Renderer/WebGLConstants', '../Shaders/PointPrimitiveCollectionFS', '../Shaders/PointPrimitiveCollectionVS', './BlendingState', @@ -49,6 +50,7 @@ define([ ShaderProgram, ShaderSource, VertexArrayFacade, + WebGLConstants, PointPrimitiveCollectionFS, PointPrimitiveCollectionVS, BlendingState, @@ -852,7 +854,8 @@ define([ if (!defined(this._rs)) { this._rs = RenderState.fromCache({ depthTest : { - enabled : true + enabled : true, + func : WebGLConstants.LEQUAL }, blending : BlendingState.ALPHA_BLEND }); From eeb284c149a81a7b80bde28117ca17a0328afde1 Mon Sep 17 00:00:00 2001 From: Ed Mackey Date: Tue, 22 Nov 2016 12:11:15 -0500 Subject: [PATCH 4/8] Apply textureAtlas border to the outer edges of atlas. Previously, it was only applied between textures within the interior of the atlas, not on the lower and left sides. It was effectively applied on the upper and right sides, since each interior texture has its own border on the upper and right sides. --- Source/Scene/TextureAtlas.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Source/Scene/TextureAtlas.js b/Source/Scene/TextureAtlas.js index adf579f2c555..5fc494f86d91 100644 --- a/Source/Scene/TextureAtlas.js +++ b/Source/Scene/TextureAtlas.js @@ -171,18 +171,19 @@ define([ var context = textureAtlas._context; var numImages = textureAtlas.numberOfImages; var scalingFactor = 2.0; + var borderWidthInPixels = textureAtlas._borderWidthInPixels; if (numImages > 0) { var oldAtlasWidth = textureAtlas._texture.width; var oldAtlasHeight = textureAtlas._texture.height; - var atlasWidth = scalingFactor * (oldAtlasWidth + image.width + textureAtlas._borderWidthInPixels); - var atlasHeight = scalingFactor * (oldAtlasHeight + image.height + textureAtlas._borderWidthInPixels); + var atlasWidth = scalingFactor * (oldAtlasWidth + image.width + borderWidthInPixels); + var atlasHeight = scalingFactor * (oldAtlasHeight + image.height + borderWidthInPixels); var widthRatio = oldAtlasWidth / atlasWidth; var heightRatio = oldAtlasHeight / atlasHeight; // Create new node structure, putting the old root node in the bottom left. - var nodeBottomRight = new TextureAtlasNode(new Cartesian2(oldAtlasWidth + textureAtlas._borderWidthInPixels, 0.0), new Cartesian2(atlasWidth, oldAtlasHeight)); + var nodeBottomRight = new TextureAtlasNode(new Cartesian2(oldAtlasWidth + borderWidthInPixels, borderWidthInPixels), new Cartesian2(atlasWidth, oldAtlasHeight)); var nodeBottomHalf = new TextureAtlasNode(new Cartesian2(), new Cartesian2(atlasWidth, oldAtlasHeight), textureAtlas._root, nodeBottomRight); - var nodeTopHalf = new TextureAtlasNode(new Cartesian2(0.0, oldAtlasHeight + textureAtlas._borderWidthInPixels), new Cartesian2(atlasWidth, atlasHeight)); + var nodeTopHalf = new TextureAtlasNode(new Cartesian2(borderWidthInPixels, oldAtlasHeight + borderWidthInPixels), new Cartesian2(atlasWidth, atlasHeight)); var nodeMain = new TextureAtlasNode(new Cartesian2(), new Cartesian2(atlasWidth, atlasHeight), nodeBottomHalf, nodeTopHalf); // Resize texture coordinates. @@ -219,8 +220,8 @@ define([ textureAtlas._root = nodeMain; } else { // First image exceeds initialSize - var initialWidth = scalingFactor * (image.width + textureAtlas._borderWidthInPixels); - var initialHeight = scalingFactor * (image.height + textureAtlas._borderWidthInPixels); + var initialWidth = scalingFactor * (image.width + 2 * borderWidthInPixels); + var initialHeight = scalingFactor * (image.height + 2 * borderWidthInPixels); if(initialWidth < textureAtlas._initialSize.x) { initialWidth = textureAtlas._initialSize.x; } @@ -234,7 +235,8 @@ define([ height : initialHeight, pixelFormat : textureAtlas._pixelFormat }); - textureAtlas._root = new TextureAtlasNode(new Cartesian2(), new Cartesian2(initialWidth, initialHeight)); + textureAtlas._root = new TextureAtlasNode(new Cartesian2(borderWidthInPixels, borderWidthInPixels), + new Cartesian2(initialWidth, initialHeight)); } } @@ -457,7 +459,7 @@ define([ * * @example * atlas = atlas && atlas.destroy(); - * + * * @see TextureAtlas#isDestroyed */ TextureAtlas.prototype.destroy = function() { From 3703161da5421848e2c04a97ac864e35dce9150b Mon Sep 17 00:00:00 2001 From: Ed Mackey Date: Tue, 22 Nov 2016 14:47:39 -0500 Subject: [PATCH 5/8] Update tests to account for new padding in TextureAtlas. --- Specs/Data/Images/Blue2x2.png | Bin 0 -> 888 bytes Specs/Data/Images/Green2x2.png | Bin 0 -> 119 bytes Specs/Data/Images/White2x2.png | Bin 0 -> 119 bytes Specs/Scene/BillboardCollectionSpec.js | 18 +++++++------- Specs/Scene/TextureAtlasSpec.js | 32 ++++++++++++------------- 5 files changed, 25 insertions(+), 25 deletions(-) create mode 100644 Specs/Data/Images/Blue2x2.png create mode 100644 Specs/Data/Images/Green2x2.png create mode 100644 Specs/Data/Images/White2x2.png diff --git a/Specs/Data/Images/Blue2x2.png b/Specs/Data/Images/Blue2x2.png new file mode 100644 index 0000000000000000000000000000000000000000..e604f8cbee004d7f9bd12deedd42c6c5a29bbc87 GIT binary patch literal 888 zcmeAS@N?(olHy`uVBq!ia0vp^Od!m`3?yAM{)#a$Ff#=Bgt#&={0EARg3%BdnIUl8 zI4cV1bIt;f$YKTtZeb8+WSBKa0w~B{;_2(k{(xIdm`%-zb-NN!h}+Y}F@)oKasmS* Y0|OfaW7?OKIY40sPgg&ebxsLQ0I|#$&j0`b literal 0 HcmV?d00001 diff --git a/Specs/Data/Images/Green2x2.png b/Specs/Data/Images/Green2x2.png new file mode 100644 index 0000000000000000000000000000000000000000..2247add0559e909a0711f09cbf954b4e68b6d161 GIT binary patch literal 119 zcmeAS@N?(olHy`uVBq!ia0vp^Od!kwBL7~QRScv!3p^r$G`BDaGcwGYBLNg-FY)ws zWq-geCd_IvS^Z`cP)N+v#W95AdUDE-^9O+72#7eqz`!HN$n3fzW)n~agQu&X%Q~lo FCIHSE9_au8 literal 0 HcmV?d00001 diff --git a/Specs/Data/Images/White2x2.png b/Specs/Data/Images/White2x2.png new file mode 100644 index 0000000000000000000000000000000000000000..7ea0256ddd340f0b4e373d92a7fa9dabd0e5003f GIT binary patch literal 119 zcmeAS@N?(olHy`uVBq!ia0vp^Od!kwBL7~QRScv!3p^r$G`BDaGcwGYBLNg-FY)ws zWq-geCd|dXI)6ztP)N+v#W95Adh(zD|LvKXnT3HE2pCk@m>KuVJ>CUW!QkoY=d#Wz Gp$Pye#2ESj literal 0 HcmV?d00001 diff --git a/Specs/Scene/BillboardCollectionSpec.js b/Specs/Scene/BillboardCollectionSpec.js index c953eb6e1625..cf768ef2b629 100644 --- a/Specs/Scene/BillboardCollectionSpec.js +++ b/Specs/Scene/BillboardCollectionSpec.js @@ -73,13 +73,13 @@ defineSuite([ camera = scene.camera; return when.join( - loadImage('./Data/Images/Green.png').then(function(result) { + loadImage('./Data/Images/Green2x2.png').then(function(result) { greenImage = result; }), - loadImage('./Data/Images/Blue.png').then(function(result) { + loadImage('./Data/Images/Blue2x2.png').then(function(result) { blueImage = result; }), - loadImage('./Data/Images/White.png').then(function(result) { + loadImage('./Data/Images/White2x2.png').then(function(result) { whiteImage = result; }), loadImage('./Data/Images/Blue10x10.png').then(function(result) { @@ -1438,11 +1438,11 @@ defineSuite([ scene.renderForSpecs(); var one = billboards.add({ - image : './Data/Images/Green.png' + image : './Data/Images/Green2x2.png' }); expect(one.ready).toEqual(false); - expect(one.image).toEqual('./Data/Images/Green.png'); + expect(one.image).toEqual('./Data/Images/Green2x2.png'); return pollToPromise(function() { return one.ready; @@ -1501,18 +1501,18 @@ defineSuite([ scene.renderForSpecs(); var one = billboards.add({ - image : './Data/Images/Green.png' + image : './Data/Images/Green2x2.png' }); expect(one.ready).toEqual(false); - expect(one.image).toEqual('./Data/Images/Green.png'); + expect(one.image).toEqual('./Data/Images/Green2x2.png'); return pollToPromise(function() { return one.ready; }).then(function() { expect(scene.renderForSpecs()).toEqual([0, 255, 0, 255]); - one.image = './Data/Images/Green.png'; + one.image = './Data/Images/Green2x2.png'; expect(one.ready).toEqual(true); expect(scene.renderForSpecs()).toEqual([0, 255, 0, 255]); @@ -1571,7 +1571,7 @@ defineSuite([ var one = billboards.add({ image : './Data/Images/Red16x16.png', - imageSubRegion : new BoundingRectangle(0.0, 0.0, 1.0, 2.0) + imageSubRegion : new BoundingRectangle(0.0, 0.0, 2.0, 3.0) }); expect(one.ready).toEqual(false); diff --git a/Specs/Scene/TextureAtlasSpec.js b/Specs/Scene/TextureAtlasSpec.js index 2d2a81c164aa..d4bff44d253d 100644 --- a/Specs/Scene/TextureAtlasSpec.js +++ b/Specs/Scene/TextureAtlasSpec.js @@ -194,8 +194,8 @@ void main() {\n\ expect(texture.height).toEqual(atlasHeight); var coords = atlas.textureCoordinates[index]; - expect(coords.x).toEqual(0.0 / atlasWidth); - expect(coords.y).toEqual(0.0 / atlasHeight); + expect(coords.x).toEqual(1.0 / atlasWidth); + expect(coords.y).toEqual(1.0 / atlasHeight); expect(coords.width).toEqual(1.0 / atlasWidth); expect(coords.height).toEqual(1.0 / atlasHeight); }); @@ -383,23 +383,23 @@ void main() {\n\ expect(texture.width).toEqual(atlasWidth); expect(texture.height).toEqual(atlasHeight); - expect(c0.x).toEqualEpsilon(0.0 / atlasWidth, CesiumMath.EPSILON16); - expect(c0.y).toEqualEpsilon(0.0 / atlasHeight, CesiumMath.EPSILON16); + expect(c0.x).toEqualEpsilon(2.0 / atlasWidth, CesiumMath.EPSILON16); + expect(c0.y).toEqualEpsilon(2.0 / atlasHeight, CesiumMath.EPSILON16); expect(c0.width).toEqualEpsilon(greenImage.width / atlasWidth, CesiumMath.EPSILON16); expect(c0.height).toEqualEpsilon(greenImage.height / atlasHeight, CesiumMath.EPSILON16); - expect(c1.x).toEqualEpsilon((greenImage.width + atlas.borderWidthInPixels) / atlasWidth, CesiumMath.EPSILON16); - expect(c1.y).toEqualEpsilon(0.0 / atlasHeight, CesiumMath.EPSILON16); + expect(c1.x).toEqualEpsilon((greenImage.width + 2 * atlas.borderWidthInPixels) / atlasWidth, CesiumMath.EPSILON16); + expect(c1.y).toEqualEpsilon(2.0 / atlasHeight, CesiumMath.EPSILON16); expect(c1.width).toEqualEpsilon(blueImage.width / atlasWidth, CesiumMath.EPSILON16); expect(c1.height).toEqualEpsilon(blueImage.width / atlasHeight, CesiumMath.EPSILON16); - expect(c2.x).toEqualEpsilon((bigRedImage.width + atlas.borderWidthInPixels) / atlasWidth, CesiumMath.EPSILON16); - expect(c2.y).toEqualEpsilon(0.0 / atlasHeight, CesiumMath.EPSILON16); + expect(c2.x).toEqualEpsilon(2.0 / atlasWidth, CesiumMath.EPSILON16); + expect(c2.y).toEqualEpsilon((bigRedImage.height + atlas.borderWidthInPixels) / atlasHeight, CesiumMath.EPSILON16); expect(c2.width).toEqualEpsilon(bigRedImage.width / atlasWidth, CesiumMath.EPSILON16); expect(c2.height).toEqualEpsilon(bigRedImage.height / atlasHeight, CesiumMath.EPSILON16); - expect(c3.x).toEqualEpsilon(0.0 / atlasWidth, CesiumMath.EPSILON16); - expect(c3.y).toEqualEpsilon((greenImage.height + atlas.borderWidthInPixels) / atlasHeight, CesiumMath.EPSILON16); + expect(c3.x).toEqualEpsilon(2.0 / atlasWidth, CesiumMath.EPSILON16); + expect(c3.y).toEqualEpsilon((greenImage.height + 2 * atlas.borderWidthInPixels) / atlasHeight, CesiumMath.EPSILON16); expect(c3.width).toEqualEpsilon(bigBlueImage.width / atlasWidth, CesiumMath.EPSILON16); expect(c3.height).toEqualEpsilon(bigBlueImage.height / atlasHeight, CesiumMath.EPSILON16); }); @@ -577,20 +577,20 @@ void main() {\n\ var texture = atlas.texture; var coordinates = atlas.textureCoordinates; - var atlasWidth = 6.0; - var atlasHeight = 6.0; + var atlasWidth = 10.0; + var atlasHeight = 10.0; expect(atlas.borderWidthInPixels).toEqual(2); expect(atlas.numberOfImages).toEqual(2); expect(texture.width).toEqual(atlasWidth); expect(texture.height).toEqual(atlasHeight); - expect(coordinates[greenIndex].x).toEqual(0.0 / atlasWidth); - expect(coordinates[greenIndex].y).toEqual(0.0 / atlasHeight); + expect(coordinates[greenIndex].x).toEqual(atlas.borderWidthInPixels / atlasWidth); + expect(coordinates[greenIndex].y).toEqual(atlas.borderWidthInPixels / atlasHeight); expect(coordinates[greenIndex].width).toEqual(1.0 / atlasWidth); expect(coordinates[greenIndex].height).toEqual(1.0 / atlasHeight); - expect(coordinates[blueIndex].x).toEqual(3.0 / atlasWidth); - expect(coordinates[blueIndex].y).toEqual(0.0 / atlasHeight); + expect(coordinates[blueIndex].x).toEqual(5.0 / atlasWidth); + expect(coordinates[blueIndex].y).toEqual(2.0 / atlasHeight); expect(coordinates[blueIndex].width).toEqual(1.0 / atlasWidth); expect(coordinates[blueIndex].height).toEqual(1.0 / atlasHeight); }); From 0ac1c5ddc5b803a9ed4816f37fe3afdbf8236079 Mon Sep 17 00:00:00 2001 From: Ed Mackey Date: Tue, 22 Nov 2016 15:06:37 -0500 Subject: [PATCH 6/8] CHANGES.md and a typo. --- CHANGES.md | 3 +++ Source/Core/writeTextToCanvas.js | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index c7beedadb6b5..74abd62cc376 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,9 @@ Change Log * * Improved terrain/imagery load ordering, especially when the terrain is already fully loaded and we add a new imagery layer. This results in a 25% reduction in load times in many cases. * Billboard depth testing changed from `LESS` to `LEQUAL`, allowing label glyphs of equal depths to overlap. +* Billboard sizes were incorrectly rounded up from odd values to even values. This has been corrected, and as a result, odd-width and odd-height billboards will appear one pixel smaller than before. +* Label glyph positions have been adjusted and corrected. +* `TextureAtlas.borderWidthInPixels` has always been applied to the upper and right edges of each internal texture, but is now also applied to the bottom and left edges of the entire TextureAtlas, guaranteeing borders on all sides regardless of position within the atlas. * Added support for saving html and css in Github Gists. [#4125](https://github.com/AnalyticalGraphicsInc/cesium/issues/4125) * Fixed `Cartographic.fromCartesian` when the cartesian is not on the ellipsoid surface. [#4611](https://github.com/AnalyticalGraphicsInc/cesium/issues/4611) diff --git a/Source/Core/writeTextToCanvas.js b/Source/Core/writeTextToCanvas.js index 581757904556..16645a18a30f 100644 --- a/Source/Core/writeTextToCanvas.js +++ b/Source/Core/writeTextToCanvas.js @@ -93,7 +93,7 @@ define([ canvas.style.visibility = ''; //Some characters, such as the letter j, have a non-zero starting position. - //This value is used for kering later, but we need to take it into account + //This value is used for kerning later, but we need to take it into account //now in order to draw the text completely on the canvas var x = -dimensions.bounds.minx; From 455a04dac0ded863c1201f4726821e7072bc1a51 Mon Sep 17 00:00:00 2001 From: Ed Mackey Date: Tue, 22 Nov 2016 15:23:16 -0500 Subject: [PATCH 7/8] Fix missing padding caught by unit test. --- Source/Core/writeTextToCanvas.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Core/writeTextToCanvas.js b/Source/Core/writeTextToCanvas.js index 16645a18a30f..c54ee0feaf90 100644 --- a/Source/Core/writeTextToCanvas.js +++ b/Source/Core/writeTextToCanvas.js @@ -98,12 +98,12 @@ define([ var x = -dimensions.bounds.minx; //Expand the width to include the starting position. - var width = Math.ceil(dimensions.width) + x; + var width = Math.ceil(dimensions.width) + x + doublePadding; //While the height of the letter is correct, we need to adjust //where we start drawing it so that letters like j and y properly dip //below the line. - var height = dimensions.height + padding; + var height = dimensions.height + doublePadding; var baseline = height - dimensions.ascent + doublePadding; var y = height - baseline + doublePadding; From 8a8799cd138c0ff91f715c30ceab92614d6c6ff4 Mon Sep 17 00:00:00 2001 From: Ed Mackey Date: Wed, 23 Nov 2016 15:14:52 -0500 Subject: [PATCH 8/8] Changes per review. --- CHANGES.md | 2 +- Source/Shaders/BillboardCollectionVS.glsl | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 74abd62cc376..4e0d169780ac 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,7 +7,7 @@ Change Log * Breaking changes * * Improved terrain/imagery load ordering, especially when the terrain is already fully loaded and we add a new imagery layer. This results in a 25% reduction in load times in many cases. -* Billboard depth testing changed from `LESS` to `LEQUAL`, allowing label glyphs of equal depths to overlap. +* Billboard, Label, and PointPrimitive depth testing changed from `LESS` to `LEQUAL`, allowing label glyphs of equal depths to overlap. * Billboard sizes were incorrectly rounded up from odd values to even values. This has been corrected, and as a result, odd-width and odd-height billboards will appear one pixel smaller than before. * Label glyph positions have been adjusted and corrected. * `TextureAtlas.borderWidthInPixels` has always been applied to the upper and right edges of each internal texture, but is now also applied to the bottom and left edges of the entire TextureAtlas, guaranteeing borders on all sides regardless of position within the atlas. diff --git a/Source/Shaders/BillboardCollectionVS.glsl b/Source/Shaders/BillboardCollectionVS.glsl index 3469a2165be4..c56ebd30516c 100644 --- a/Source/Shaders/BillboardCollectionVS.glsl +++ b/Source/Shaders/BillboardCollectionVS.glsl @@ -38,6 +38,8 @@ const float SHIFT_RIGHT1 = 1.0 / 2.0; vec4 computePositionWindowCoordinates(vec4 positionEC, vec2 imageSize, float scale, vec2 direction, vec2 origin, vec2 translate, vec2 pixelOffset, vec3 alignedAxis, bool validAlignedAxis, float rotation, bool sizeInMeters) { + // Note the halfSize cannot be computed in JavaScript because it is sent via + // compressed vertex attributes that coerce it to an integer. vec2 halfSize = imageSize * scale * czm_resolutionScale * 0.5; halfSize *= ((direction * 2.0) - 1.0);