Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

three-bmfont-text

Package Overview
Dependencies
Maintainers
1
Versions
19
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

three-bmfont-text - npm Package Compare versions

Comparing version 1.2.0 to 2.0.0

lib/vertices.js

213

index.js
var createLayout = require('layout-bmfont-text')
var inherits = require('inherits')
var createIndices = require('quad-indices')
var buffer = require('three-buffer-vertex-data')
var assign = require('object-assign')
var vertices = require('./lib/vertices')
var utils = require('./lib/utils')

@@ -8,84 +12,85 @@

module.exports = function(opt) {
return new TextMesh(opt)
module.exports = function createTextGeometry (opt) {
return new TextGeometry(opt)
}
function TextMesh(opt) {
function TextGeometry (opt) {
Base.call(this)
var multipage = opt && opt.multipage
this.layout = null
this._positions = new THREE.BufferAttribute(null, 2)
this._uvs = new THREE.BufferAttribute(null, 2)
if (multipage)
this._pages = new THREE.BufferAttribute(null, 1)
this._indices = new THREE.BufferAttribute(null, 1)
if (typeof opt === 'string') {
opt = { text: opt }
}
if (opt)
this.update(opt)
// use these as default values for any subsequent
// calls to update()
this._opt = assign({}, opt)
this.addAttribute('position', this._positions)
this.addAttribute('uv', this._uvs)
if (multipage)
this.addAttribute('page', this._pages)
this.addAttribute('index', this._indices)
// also do an initial setup...
if (opt) this.update(opt)
}
inherits(TextMesh, Base)
inherits(TextGeometry, Base)
TextMesh.prototype.update = function(opt) {
opt = opt||{}
this.layout = createLayout(opt)
TextGeometry.prototype.update = function (opt) {
if (typeof opt === 'string') {
opt = { text: opt }
}
//don't allow a deferred creation of multipage
//since it requires different buffer layout
if (opt.multipage && !this._pages) {
throw new Error('must specify multipage: true in constructor')
// use constructor defaults
opt = assign({}, this._opt, opt)
if (!opt.font) {
throw new TypeError('must specify a { font } in options')
}
this.layout = createLayout(opt)
// get vec2 texcoords
var flipY = opt.flipY !== false
// the desired BMFont data
var font = opt.font
//determine texture size from font file
// determine texture size from font file
var texWidth = font.common.scaleW
var texHeight = font.common.scaleH
//get visible glyphs
var glyphs = this.layout.glyphs.filter(function(glyph) {
// get visible glyphs
var glyphs = this.layout.glyphs.filter(function (glyph) {
var bitmap = glyph.data
return bitmap.width * bitmap.height > 0
})
//provide visible glyphs for convenience
this.visibleGlyphs = glyphs;
//get vec2 quad positions
var positions = getQuadPositions(glyphs, this.layout)
// provide visible glyphs for convenience
this.visibleGlyphs = glyphs
//get vec2 texcoords
var flipY = opt.flipY !== false
var uvs = getQuadUVs(glyphs, texWidth, texHeight, flipY)
if (opt.multipage) {
var pages = getQuadPages(glyphs)
this._pages.array = pages
this._pages.needsUpdate = true
}
// get common vertex data
var positions = vertices.positions(glyphs)
var uvs = vertices.uvs(glyphs, texWidth, texHeight, flipY)
var indices = createIndices({
clockwise: true,
type: 'uint16',
count: glyphs.length
})
//get indices
var quadCount = glyphs.length
var indices = createIndices({ clockwise: true, count: quadCount })
// update vertex data
buffer.index(this, indices, 1, 'uint16')
buffer.attr(this, 'position', positions, 2)
buffer.attr(this, 'uv', uvs, 2)
this._uvs.array = uvs
this._uvs.needsUpdate = true
this._indices.array = indices
this._indices.needsUpdate = true
this._positions.array = positions
this._positions.needsUpdate = true
// update multipage data
if (!opt.multipage && 'page' in this.attributes) {
// disable multipage rendering
this.removeAttribute('page')
} else if (opt.multipage) {
var pages = vertices.pages(glyphs)
// enable multipage rendering
buffer.attr(this, 'page', pages, 1)
}
}
TextMesh.prototype.computeBoundingSphere = function() {
if (this.boundingSphere === null)
this.boundingSphere = new THREE.Sphere()
TextGeometry.prototype.computeBoundingSphere = function () {
if (this.boundingSphere === null) {
this.boundingSphere = new THREE.Sphere()
}

@@ -100,11 +105,13 @@ var positions = this.attributes.position.array

utils.computeSphere(positions, this.boundingSphere)
if (isNaN(this.boundingSphere.radius))
console.error('THREE.BufferGeometry.computeBoundingSphere(): '
+ 'Computed radius is NaN. The '
+ '"position" attribute is likely to have NaN values.')
if (isNaN(this.boundingSphere.radius)) {
console.error('THREE.BufferGeometry.computeBoundingSphere(): ' +
'Computed radius is NaN. The ' +
'"position" attribute is likely to have NaN values.')
}
}
TextMesh.prototype.computeBoundingBox = function() {
if (this.boundingBox === null)
this.boundingBox = new THREE.Box3()
TextGeometry.prototype.computeBoundingBox = function () {
if (this.boundingBox === null) {
this.boundingBox = new THREE.Box3()
}

@@ -120,81 +127,1 @@ var bbox = this.boundingBox

}
function getQuadPages(glyphs) {
var pages = new Float32Array(glyphs.length * 4 * 1)
var i = 0
glyphs.forEach(function(glyph) {
var id = glyph.data.page || 0
pages[i++] = id
pages[i++] = id
pages[i++] = id
pages[i++] = id
})
return pages
}
function getQuadUVs(glyphs, texWidth, texHeight, flipY) {
var uvs = new Float32Array(glyphs.length * 4 * 2)
var i = 0
glyphs.forEach(function(glyph) {
var bitmap = glyph.data
var bw = (bitmap.x+bitmap.width)
var bh = (bitmap.y+bitmap.height)
//top left position
var u0 = bitmap.x / texWidth
var v1 = bitmap.y / texHeight
var u1 = bw / texWidth
var v0 = bh / texHeight
if (flipY) {
v1 = (texHeight-bitmap.y) / texHeight
v0 = (texHeight-bh) / texHeight
}
//BL
uvs[i++] = u0
uvs[i++] = v1
//TL
uvs[i++] = u0
uvs[i++] = v0
//TR
uvs[i++] = u1
uvs[i++] = v0
//BR
uvs[i++] = u1
uvs[i++] = v1
})
return uvs
}
function getQuadPositions(glyphs, layout) {
var positions = new Float32Array(glyphs.length * 4 * 2)
var i = 0
glyphs.forEach(function(glyph) {
var bitmap = glyph.data
//bottom left position
var x = glyph.position[0] + bitmap.xoffset
var y = glyph.position[1] + bitmap.yoffset
//quad size
var w = bitmap.width
var h = bitmap.height
//BL
positions[i++] = x
positions[i++] = y
//TL
positions[i++] = x
positions[i++] = y + h
//TR
positions[i++] = x + w
positions[i++] = y + h
//BR
positions[i++] = x + w
positions[i++] = y
})
return positions
}
var itemSize = 2
var box = { min: [0, 0], max: [0, 0] }
function bounds(positions) {
function bounds (positions) {
var count = positions.length / itemSize

@@ -11,3 +11,3 @@ box.min[0] = positions[0]

for (var i=0; i<count; i++) {
for (var i = 0; i < count; i++) {
var x = positions[i * itemSize + 0]

@@ -22,18 +22,19 @@ var y = positions[i * itemSize + 1]

module.exports.computeBox = function(positions, output) {
module.exports.computeBox = function (positions, output) {
bounds(positions)
output.min.set(box.min[0], box.min[1], 0)
output.min.set(box.min[0], box.min[1], 0)
output.max.set(box.max[0], box.max[1], 0)
}
module.exports.computeSphere = function(positions, output) {
module.exports.computeSphere = function (positions, output) {
bounds(positions)
var minX = box.min[0], minY = box.min[1],
maxX = box.max[0], maxY = box.max[1],
width = maxX - minX,
height = maxY - minY,
length = Math.sqrt(width*width + height*height)
output.center.set(minX + width/2, minY + height/2, 0)
output.radius = length/2
var minX = box.min[0]
var minY = box.min[1]
var maxX = box.max[0]
var maxY = box.max[1]
var width = maxX - minX
var height = maxY - minY
var length = Math.sqrt(width * width + height * height)
output.center.set(minX + width / 2, minY + height / 2, 0)
output.radius = length / 2
}
{
"name": "three-bmfont-text",
"version": "1.2.0",
"version": "2.0.0",
"description": "renders BMFont files in ThreeJS with word-wrapping",

@@ -12,24 +12,31 @@ "main": "index.js",

},
"standard": {
"globals": [
"THREE"
]
},
"dependencies": {
"inherits": "^2.0.1",
"layout-bmfont-text": "^1.2.0",
"object-assign": "^4.0.1",
"quad-indices": "^2.0.1",
"xtend": "^4.0.0"
"three-buffer-vertex-data": "^1.0.0"
},
"devDependencies": {
"bluebird": "^2.9.14",
"browserify": "^9.0.3",
"budo": "^1.2.2",
"garnish": "^2.1.0",
"browserify": "^12.0.1",
"budo": "^7.0.2",
"load-bmfont": "^1.0.0",
"standard": "^5.4.1",
"three": "^0.70.0",
"three-orbit-viewer": "^69.2.9",
"uglify-js": "^2.4.17",
"watchify": "^2.4.0"
"uglify-js": "^2.4.17"
},
"scripts": {
"build": "browserify test/test-3d.js | uglifyjs -cm > test/bundle.js",
"test-2d": "budo test/test-2d.js -o bundle.js --dir test --live -d | garnish -v",
"test-3d": "budo test/test-3d.js -o bundle.js --dir test --live -d | garnish -v",
"test-multi": "budo test/test-multi.js -o bundle.js --dir test --live -d | garnish -v"
"start": "budo test/test-line.js:bundle.js --dir test --live",
"test-2d": "budo test/test-2d.js:bundle.js --dir test --live",
"test-3d": "budo test/test-3d.js:bundle.js --dir test --live",
"test-multi": "budo test/test-multi.js:bundle.js --dir test --live",
"test": "standard"
},

@@ -36,0 +43,0 @@ "keywords": [

@@ -9,4 +9,6 @@ # three-bmfont-text

Bitmap font rendering for ThreeJS, batching glyphs into a single BufferGeometry. Supports word-wrapping, letter spacing, kerning, signed distance fields, multi-texture fonts, and more. About 8kb after minification.
Bitmap font rendering for ThreeJS, batching glyphs into a single BufferGeometry. Supports word-wrapping, letter spacing, kerning, signed distance fields with standard derivatives, multi-texture fonts, and more. About 12kb after minification.
Works on Three r69-73, and possibly more.
Below is an example that uses [load-bmfont](https://www.npmjs.com/package/load-bmfont) to parse BMFont files on the fly with XHR:

@@ -19,6 +21,5 @@

loadFont('fonts/Arial.fnt', function(err, font) {
//create a geometry of packed bitmap glyphs,
//word wrapped to 300px and right-aligned
// create a geometry of packed bitmap glyphs,
// word wrapped to 300px and right-aligned
var geometry = createGeometry({
text: 'Lorem ipsum\nDolor sit amet.',
width: 300,

@@ -28,11 +29,16 @@ align: 'right',

})
// change text and other options as desired
// the options sepcified in constructor will
// be used as defaults
geometry.update('Lorem ipsum\nDolor sit amet.')
//the resulting layout has metrics and bounds
// the resulting layout has metrics and bounds
console.log(geometry.layout.height)
console.log(geometry.layout.descender)
//the texture atlas containing our glyphs
// the texture atlas containing our glyphs
var texture = THREE.ImageUtils.loadTexture('fonts/Arial.png')
//We can use plain old bitmap materials
// we can use a simple ThreeJS material
var material = new THREE.MeshBasicMaterial({

@@ -44,3 +50,3 @@ map: texture,

//now do something with our text mesh !
// now do something with our mesh!
var mesh = new THREE.Mesh(geometry, material)

@@ -58,4 +64,10 @@ })

Returns a new BufferGeometry with the given options. The ThreeJS-specific options:
Returns a new BufferGeometry with the given options.
**Note:** The options set in the constructor become the defaults for any subsequent calls to `update()`.
`opt` can be an options object, or a String – equivalent to `{ text: str }`.
Options specific to ThreeJS:
- `flipY` (boolean) whether the texture will be Y-flipped (default true)

@@ -79,6 +91,12 @@ - `multipage` (boolean) whether to construct this geometry with an extra buffer containing page IDs. This is necessary for multi-texture fonts (default false)

Re-builds the geometry using the given options. All options are the same as in the constructor, except for `multipage` which must be specified during construction-time.
Re-builds the geometry using the given options. Any options not specified here will default to those set in the constructor.
This method will recompute the text layout and rebuild the WebGL buffers.
`opt` can be a string, which is equivalent to:
```js
geometry.update({ text: 'new text' })
```
#### `geometry.layout`

@@ -92,3 +110,3 @@

This is an array of `{ line, position, index, data }` objects, [see here](https://github.com/Jam3/layout-bmfont-text#layoutglyphs). For example, this could be used to add a new BufferAttribuet for `line` offset.
This is an array of `{ line, position, index, data }` objects, [see here](https://github.com/Jam3/layout-bmfont-text#layoutglyphs). For example, this could be used to add a new BufferAttribute for `line` offset.

@@ -139,4 +157,17 @@ ## Demos

## Change Log
- `2.0.0`
- now uses [three-buffer-vertex-data](https://github.com/Jam3/three-buffer-vertex-data) to handle some ThreeJS version differences; this may lead to a slight memory increase
- constructor holds default options for subsequent calls to `update()`
- `update()` and constructor can take string, treated as `{ text: str }`
- changed to `RawShaderMaterial` for proper ThreeJS support across versions
- SDF shader now uses standard derivatives by default for better anti-aliasing, with a fall back using `gl_FragCoord.w`
- SDF shader `smooth` option has been removed for less API surface area
- `1.x`
- uses `ShaderMaterial`, only really supports r69
- must call `update()` with *all* options desired
## License
MIT, see [LICENSE.md](http://github.com/Jam3/three-bmfont-text/blob/master/LICENSE.md) for details.

@@ -1,6 +0,8 @@

var xtend = require('xtend')
var assign = require('object-assign')
module.exports = function(opt) {
opt = opt||{}
module.exports = function (opt) {
opt = opt || {}
var opacity = typeof opt.opacity === 'number' ? opt.opacity : 1
var precision = opt.precision || 'highp'
var alphaTest = typeof opt.alphaTest === 'number' ? opt.alphaTest : 0.0001

@@ -11,5 +13,5 @@ var textures = opt.textures || []

var baseUniforms = {}
textures.forEach(function(tex, i) {
baseUniforms['texture' + i] = {
type: 't',
textures.forEach(function (tex, i) {
baseUniforms['texture' + i] = {
type: 't',
value: tex

@@ -19,49 +21,68 @@ }

var samplers = textures.map(function(tex, i) {
return 'uniform sampler2D texture'+i+';'
var samplers = textures.map(function (tex, i) {
return 'uniform sampler2D texture' + i + ';'
}).join('\n')
var body = textures.map(function(tex, i) {
var cond = i===0 ? 'if' : 'else if'
var body = textures.map(function (tex, i) {
var cond = i === 0 ? 'if' : 'else if'
return [
cond+" (vPage == "+i+".0) {",
"sampleColor = texture2D(texture"+i+", vUv);",
"}"
cond + ' (vPage == ' + i + '.0) {',
'sampleColor = texture2D(texture' + i + ', vUv);',
'}'
].join('\n')
}).join('\n')
return xtend({
uniforms: xtend(baseUniforms, {
var color = opt.color
// remove to satisfy r73
delete opt.textures
delete opt.color
delete opt.precision
delete opt.opacity
var attributes = {
attributes: { page: { type: 'f', value: 0 } }
}
var threeVers = (parseInt(THREE.REVISION, 10) || 0) | 0
if (threeVers >= 72) {
attributes = undefined
}
return assign({
uniforms: assign({}, baseUniforms, {
opacity: { type: 'f', value: opacity },
color: { type: 'c', value: new THREE.Color(opt.color) }
color: { type: 'c', value: new THREE.Color(color) }
}),
attributes: {
page: { type: 'f', value: 0 }
},
vertexShader: [
"attribute float page;",
"varying vec2 vUv;",
"varying float vPage;",
"void main() {",
"vUv = uv;",
"vPage = page;",
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position.xyz, 1.0 );",
"}"
].join("\n"),
fragmentShader: [
"uniform float opacity;",
"uniform vec3 color;",
'attribute vec4 position;',
'attribute vec2 uv;',
'attribute float page;',
'uniform mat4 projectionMatrix;',
'uniform mat4 modelViewMatrix;',
'varying vec2 vUv;',
'varying float vPage;',
'void main() {',
'vUv = uv;',
'vPage = page;',
'gl_Position = projectionMatrix * modelViewMatrix * position;',
'}'
].join('\n'),
fragmentShader: [
'precision ' + precision + ' float;',
'uniform float opacity;',
'uniform vec3 color;',
samplers,
"varying float vPage;",
"varying vec2 vUv;",
"void main() {",
"vec4 sampleColor = vec4(0.0);",
body,
"gl_FragColor = sampleColor * vec4(color, opacity);",
"}"
].join("\n"),
defines: {
"USE_MAP": ""
}
}, opt)
}
'varying float vPage;',
'varying vec2 vUv;',
'void main() {',
'vec4 sampleColor = vec4(0.0);',
body,
'gl_FragColor = sampleColor * vec4(color, opacity);',
alphaTest === 0
? ''
: ' if (gl_FragColor.a < ' + alphaTest + ') discard;',
'}'
].join('\n')
}, attributes, opt)
}

@@ -1,49 +0,63 @@

var xtend = require('xtend')
var assign = require('object-assign')
module.exports = function(opt) {
opt = opt||{}
module.exports = function (opt) {
opt = opt || {}
var opacity = typeof opt.opacity === 'number' ? opt.opacity : 1
var alphaTest = typeof opt.alphaTest === 'number' ? opt.alphaTest : 0.06
var smooth = typeof opt.smooth === 'number' ? opt.smooth : 1/16
return xtend({
var alphaTest = typeof opt.alphaTest === 'number' ? opt.alphaTest : 0.0001
var precision = opt.precision || 'highp'
var color = opt.color
var map = opt.map
// remove to satisfy r73
delete opt.map
delete opt.color
delete opt.precision
delete opt.opacity
return assign({
uniforms: {
opacity: { type: 'f', value: opacity },
smooth: { type: 'f', value: smooth },
map: { type: 't', value: opt.map || new THREE.Texture() },
color: { type: 'c', value: new THREE.Color(opt.color) }
map: { type: 't', value: map || new THREE.Texture() },
color: { type: 'c', value: new THREE.Color(color) }
},
vertexShader: [
"attribute float page;",
"varying vec2 vUv;",
"varying float vPage;",
"void main() {",
"vUv = uv;",
"vPage = page;",
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position.xyz, 1.0 );",
"}"
].join("\n"),
fragmentShader: [
'attribute vec2 uv;',
'attribute vec4 position;',
'uniform mat4 projectionMatrix;',
'uniform mat4 modelViewMatrix;',
'varying vec2 vUv;',
'void main() {',
'vUv = uv;',
'gl_Position = projectionMatrix * modelViewMatrix * position;',
'}'
].join('\n'),
fragmentShader: [
'#ifdef GL_OES_standard_derivatives',
'#extension GL_OES_standard_derivatives : enable',
'#endif',
'precision ' + precision + ' float;',
'uniform float opacity;',
'uniform vec3 color;',
'uniform sampler2D map;',
'varying vec2 vUv;',
"#define SQRT2 1.4142135623730951",
"uniform float opacity;",
"uniform vec3 color;",
"uniform sampler2D map;",
"uniform float smooth;",
"varying float vPage;",
"varying vec2 vUv;",
"void main() {",
"vec4 texColor = texture2D(map, vUv);",
"float dst = texColor.a;",
"float afwidth = smooth * SQRT2 / (2.0 * gl_FragCoord.w);",
"float alpha = smoothstep(0.5 - afwidth, 0.5 + afwidth, dst);",
'float aastep(float value) {',
' #ifdef GL_OES_standard_derivatives',
' float afwidth = length(vec2(dFdx(value), dFdy(value))) * 0.70710678118654757;',
' #else',
' float afwidth = (1.0 / 32.0) * (1.4142135623730951 / (2.0 * gl_FragCoord.w));',
' #endif',
' return smoothstep(0.5 - afwidth, 0.5 + afwidth, value);',
'}',
"gl_FragColor = vec4(color, opacity * alpha);",
THREE.ShaderChunk["alphatest_fragment"],
"}"
].join("\n"),
defines: {
"USE_MAP": "",
"ALPHATEST": Number(alphaTest || 0).toFixed(1)
}
'void main() {',
' vec4 texColor = texture2D(map, vUv);',
' float alpha = aastep(texColor.a);',
' gl_FragColor = vec4(color, opacity * alpha);',
alphaTest === 0
? ''
: ' if (gl_FragColor.a < ' + alphaTest + ') discard;',
'}'
].join('\n')
}, opt)
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc