Skip to content
Snippets Groups Projects
Commit 06f9578c authored by Alexander Rose's avatar Alexander Rose
Browse files

support background for text rendering

parent ce331b3a
Branches
Tags
No related merge requests found
...@@ -33,7 +33,10 @@ export const FontAtlasParams = { ...@@ -33,7 +33,10 @@ export const FontAtlasParams = {
export type FontAtlasParams = typeof FontAtlasParams export type FontAtlasParams = typeof FontAtlasParams
export type FontAtlasProps = PD.Values<FontAtlasParams> export type FontAtlasProps = PD.Values<FontAtlasParams>
export type FontAtlasMap = { x: number, y: number, w: number, h: number } export type FontAtlasMap = {
x: number, y: number, w: number, h: number,
nw: number, nh: number // normalized to lineheight
}
export class FontAtlas { export class FontAtlas {
readonly props: Readonly<FontAtlasProps> readonly props: Readonly<FontAtlasProps>
...@@ -120,7 +123,8 @@ export class FontAtlas { ...@@ -120,7 +123,8 @@ export class FontAtlas {
this.mapped[char] = { this.mapped[char] = {
x: this.currentX, y: this.currentY, x: this.currentX, y: this.currentY,
w: this.scratchW, h: this.scratchH w: this.scratchW, h: this.scratchH,
nw: this.scratchW / this.lineHeight, nh: this.scratchH / this.lineHeight
} }
for (let y = 0; y < this.scratchH; ++y) { for (let y = 0; y < this.scratchH; ++y) {
......
...@@ -32,11 +32,11 @@ export namespace TextBuilder { ...@@ -32,11 +32,11 @@ export namespace TextBuilder {
const { attachment, background, backgroundMargin } = p const { attachment, background, backgroundMargin } = p
const fontAtlas = getFontAtlas(p) const fontAtlas = getFontAtlas(p)
const { lineHeight } = fontAtlas const margin = (1 / 2.5) * backgroundMargin
const outline = fontAtlas.buffer / fontAtlas.lineHeight
const margin = (lineHeight * backgroundMargin * 0.1) - 10 // console.log('margin', margin)
const outline = fontAtlas.buffer // console.log('attachment', attachment)
console.log('margin', margin) // console.log('background', background)
return { return {
add: (str: string, x: number, y: number, z: number, group: number) => { add: (str: string, x: number, y: number, z: number, group: number) => {
...@@ -46,15 +46,15 @@ export namespace TextBuilder { ...@@ -46,15 +46,15 @@ export namespace TextBuilder {
// calculate width // calculate width
for (let iChar = 0; iChar < nChar; ++iChar) { for (let iChar = 0; iChar < nChar; ++iChar) {
const c = fontAtlas.get(str[iChar]) const c = fontAtlas.get(str[iChar])
xadvance += c.w - 2 * outline xadvance += c.nw - 2 * outline
} }
// attachment // attachment
let yShift: number, xShift: number let yShift: number, xShift: number
if (attachment.startsWith('top')) { if (attachment.startsWith('top')) {
yShift = lineHeight / 1.25 yShift = 1 / 1.25
} else if (attachment.startsWith('middle')) { } else if (attachment.startsWith('middle')) {
yShift = lineHeight / 2.5 yShift = 1 / 2.5
} else { } else {
yShift = 0 // "bottom" yShift = 0 // "bottom"
} }
...@@ -65,19 +65,17 @@ export namespace TextBuilder { ...@@ -65,19 +65,17 @@ export namespace TextBuilder {
} else { } else {
xShift = 0 // "left" xShift = 0 // "left"
} }
xShift += outline
yShift += outline
// background // background
if (background) { if (background) {
ChunkedArray.add2(mappings, -lineHeight / 6 - xShift - margin, lineHeight - yShift + margin) ChunkedArray.add2(mappings, -xadvance + xShift - margin - 0.1, yShift + margin) // top left
ChunkedArray.add2(mappings, -lineHeight / 6 - xShift - margin, 0 - yShift - margin) ChunkedArray.add2(mappings, -xadvance + xShift - margin - 0.1, -yShift - margin) // bottom left
ChunkedArray.add2(mappings, xadvance + lineHeight / 6 - xShift + 2 * outline + margin, lineHeight - yShift + margin) ChunkedArray.add2(mappings, xadvance - xShift + margin + 0.1, yShift + margin) // top right
ChunkedArray.add2(mappings, xadvance + lineHeight / 6 - xShift + 2 * outline + margin, 0 - yShift - margin) ChunkedArray.add2(mappings, xadvance - xShift + margin + 0.1, -yShift - margin) // bottom right
const offset = centers.elementCount const offset = centers.elementCount
for (let i = 0; i < 4; ++i) { for (let i = 0; i < 4; ++i) {
ChunkedArray.add2(tcoords, 0, 10) ChunkedArray.add2(tcoords, 10, 10)
ChunkedArray.add3(centers, x, y, z); ChunkedArray.add3(centers, x, y, z);
ChunkedArray.add(groups, group); ChunkedArray.add(groups, group);
} }
...@@ -85,15 +83,17 @@ export namespace TextBuilder { ...@@ -85,15 +83,17 @@ export namespace TextBuilder {
ChunkedArray.add3(indices, offset + quadIndices[3], offset + quadIndices[4], offset + quadIndices[5]) ChunkedArray.add3(indices, offset + quadIndices[3], offset + quadIndices[4], offset + quadIndices[5])
} }
xShift += outline
yShift += outline
xadvance = 0 xadvance = 0
for (let iChar = 0; iChar < nChar; ++iChar) { for (let iChar = 0; iChar < nChar; ++iChar) {
const c = fontAtlas.get(str[iChar]) const c = fontAtlas.get(str[iChar])
ChunkedArray.add2(mappings, xadvance - xShift, c.h - yShift) // top left ChunkedArray.add2(mappings, xadvance - xShift, c.nh - yShift) // top left
ChunkedArray.add2(mappings, xadvance - xShift, 0 - yShift) // bottom left ChunkedArray.add2(mappings, xadvance - xShift, -yShift) // bottom left
ChunkedArray.add2(mappings, xadvance + c.w - xShift, c.h - yShift) // top right ChunkedArray.add2(mappings, xadvance + c.nw - xShift, c.nh - yShift) // top right
ChunkedArray.add2(mappings, xadvance + c.w - xShift, 0 - yShift) // bottom right ChunkedArray.add2(mappings, xadvance + c.nw - xShift, -yShift) // bottom right
const texWidth = fontAtlas.texture.width const texWidth = fontAtlas.texture.width
const texHeight = fontAtlas.texture.height const texHeight = fontAtlas.texture.height
...@@ -103,7 +103,7 @@ export namespace TextBuilder { ...@@ -103,7 +103,7 @@ export namespace TextBuilder {
ChunkedArray.add2(tcoords, (c.x + c.w) / texWidth, c.y / texHeight) // top right ChunkedArray.add2(tcoords, (c.x + c.w) / texWidth, c.y / texHeight) // top right
ChunkedArray.add2(tcoords, (c.x + c.w) / texWidth, (c.y + c.h) / texHeight) // bottom right ChunkedArray.add2(tcoords, (c.x + c.w) / texWidth, (c.y + c.h) / texHeight) // bottom right
xadvance += c.w - 2 * outline xadvance += c.nw - 2 * outline
const offset = centers.elementCount const offset = centers.elementCount
for (let i = 0; i < 4; ++i) { for (let i = 0; i < 4; ++i) {
...@@ -120,10 +120,11 @@ export namespace TextBuilder { ...@@ -120,10 +120,11 @@ export namespace TextBuilder {
const ib = ChunkedArray.compact(indices, true) as Uint32Array const ib = ChunkedArray.compact(indices, true) as Uint32Array
const gb = ChunkedArray.compact(groups, true) as Float32Array const gb = ChunkedArray.compact(groups, true) as Float32Array
const tb = ChunkedArray.compact(tcoords, true) as Float32Array const tb = ChunkedArray.compact(tcoords, true) as Float32Array
const ft = fontAtlas.texture
return { return {
kind: 'text', kind: 'text',
charCount: centers.elementCount / 4, charCount: centers.elementCount / 4,
fontAtlas, fontTexture: text ? ValueCell.update(text.fontTexture, ft) : ValueCell.create(ft),
centerBuffer: text ? ValueCell.update(text.centerBuffer, cb) : ValueCell.create(cb), centerBuffer: text ? ValueCell.update(text.centerBuffer, cb) : ValueCell.create(cb),
mappingBuffer: text ? ValueCell.update(text.centerBuffer, mb) : ValueCell.create(mb), mappingBuffer: text ? ValueCell.update(text.centerBuffer, mb) : ValueCell.create(mb),
indexBuffer: text ? ValueCell.update(text.indexBuffer, ib) : ValueCell.create(ib), indexBuffer: text ? ValueCell.update(text.indexBuffer, ib) : ValueCell.create(ib),
......
...@@ -18,11 +18,11 @@ import { NullLocation } from 'mol-model/location'; ...@@ -18,11 +18,11 @@ import { NullLocation } from 'mol-model/location';
import { UniformColorTheme } from 'mol-theme/color/uniform'; import { UniformColorTheme } from 'mol-theme/color/uniform';
import { UniformSizeTheme } from 'mol-theme/size/uniform'; import { UniformSizeTheme } from 'mol-theme/size/uniform';
import { Sphere3D } from 'mol-math/geometry'; import { Sphere3D } from 'mol-math/geometry';
import { calculateBoundingSphere } from 'mol-gl/renderable/util'; import { calculateBoundingSphere, TextureImage, createTextureImage } from 'mol-gl/renderable/util';
import { TextValues } from 'mol-gl/renderable/text'; import { TextValues } from 'mol-gl/renderable/text';
import { Color } from 'mol-util/color'; import { Color } from 'mol-util/color';
import { Vec3 } from 'mol-math/linear-algebra'; import { Vec3 } from 'mol-math/linear-algebra';
import { FontAtlas, getFontAtlas, FontAtlasParams } from './font-atlas'; import { FontAtlasParams } from './font-atlas';
import { RenderableState } from 'mol-gl/renderable'; import { RenderableState } from 'mol-gl/renderable';
import { clamp } from 'mol-math/interpolate'; import { clamp } from 'mol-math/interpolate';
...@@ -35,7 +35,7 @@ export interface Text { ...@@ -35,7 +35,7 @@ export interface Text {
/** Number of characters in the text */ /** Number of characters in the text */
readonly charCount: number, readonly charCount: number,
/** Font Atlas */ /** Font Atlas */
readonly fontAtlas: FontAtlas, readonly fontTexture: ValueCell<TextureImage<Uint8Array>>,
/** Center buffer as array of xyz values wrapped in a value cell */ /** Center buffer as array of xyz values wrapped in a value cell */
readonly centerBuffer: ValueCell<Float32Array>, readonly centerBuffer: ValueCell<Float32Array>,
...@@ -56,10 +56,11 @@ export namespace Text { ...@@ -56,10 +56,11 @@ export namespace Text {
const ib = text ? text.indexBuffer.ref.value : new Uint32Array(0) const ib = text ? text.indexBuffer.ref.value : new Uint32Array(0)
const gb = text ? text.groupBuffer.ref.value : new Float32Array(0) const gb = text ? text.groupBuffer.ref.value : new Float32Array(0)
const tb = text ? text.tcoordBuffer.ref.value : new Float32Array(0) const tb = text ? text.tcoordBuffer.ref.value : new Float32Array(0)
const ft = text ? text.fontTexture.ref.value : createTextureImage(0, 1)
return { return {
kind: 'text', kind: 'text',
charCount: 0, charCount: 0,
fontAtlas: getFontAtlas({}), fontTexture: text ? ValueCell.update(text.fontTexture, ft) : ValueCell.create(ft),
centerBuffer: text ? ValueCell.update(text.centerBuffer, cb) : ValueCell.create(cb), centerBuffer: text ? ValueCell.update(text.centerBuffer, cb) : ValueCell.create(cb),
mappingBuffer: text ? ValueCell.update(text.mappingBuffer, mb) : ValueCell.create(mb), mappingBuffer: text ? ValueCell.update(text.mappingBuffer, mb) : ValueCell.create(mb),
indexBuffer: text ? ValueCell.update(text.indexBuffer, ib) : ValueCell.create(ib), indexBuffer: text ? ValueCell.update(text.indexBuffer, ib) : ValueCell.create(ib),
...@@ -75,13 +76,13 @@ export namespace Text { ...@@ -75,13 +76,13 @@ export namespace Text {
borderWidth: PD.Numeric(0, { min: 0, max: 1, step: 0.01 }), borderWidth: PD.Numeric(0, { min: 0, max: 1, step: 0.01 }),
borderColor: PD.Color(ColorNames.grey), borderColor: PD.Color(ColorNames.grey),
offsetX: PD.Numeric(1, { min: 0, max: 10, step: 0.1 }), offsetX: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }),
offsetY: PD.Numeric(1, { min: 0, max: 10, step: 0.1 }), offsetY: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }),
offsetZ: PD.Numeric(1, { min: 0, max: 10, step: 0.1 }), offsetZ: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }),
background: PD.Boolean(false), background: PD.Boolean(false),
backgroundMargin: PD.Numeric(0.2, { min: 0, max: 10, step: 0.1 }), backgroundMargin: PD.Numeric(0.2, { min: 0, max: 1, step: 0.01 }),
backgroundColor: PD.Color(ColorNames.grey), backgroundColor: PD.Color(ColorNames.grey),
backgroundOpacity: PD.Numeric(0, { min: 0, max: 1, step: 0.01 }), backgroundOpacity: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }),
attachment: PD.Select('normal', [['bottom-left', 'bottom-left'], ['bottom-center', 'bottom-center'], ['bottom-right', 'bottom-right'], ['middle-left', 'middle-left'], ['top-left', 'top-left'], ['top-center', 'top-center'], ['top-right', 'top-right']] as [TextAttachment, string][]), attachment: PD.Select('normal', [['bottom-left', 'bottom-left'], ['bottom-center', 'bottom-center'], ['bottom-right', 'bottom-right'], ['middle-left', 'middle-left'], ['top-left', 'top-left'], ['top-center', 'top-center'], ['top-right', 'top-right']] as [TextAttachment, string][]),
} }
...@@ -105,8 +106,6 @@ export namespace Text { ...@@ -105,8 +106,6 @@ export namespace Text {
transform.aTransform.ref.value, instanceCount, padding transform.aTransform.ref.value, instanceCount, padding
) )
console.log(props.sizeFactor, text.fontAtlas.lineHeight, props.fontSize)
return { return {
aPosition: text.centerBuffer, aPosition: text.centerBuffer,
aMapping: text.mappingBuffer, aMapping: text.mappingBuffer,
...@@ -120,11 +119,11 @@ export namespace Text { ...@@ -120,11 +119,11 @@ export namespace Text {
...transform, ...transform,
aTexCoord: text.tcoordBuffer, aTexCoord: text.tcoordBuffer,
tFont: ValueCell.create(text.fontAtlas.texture), tFont: text.fontTexture,
padding: ValueCell.create(padding), padding: ValueCell.create(padding),
...Geometry.createValues(props, counts), ...Geometry.createValues(props, counts),
uSizeFactor: ValueCell.create(props.sizeFactor / text.fontAtlas.lineHeight), uSizeFactor: ValueCell.create(props.sizeFactor),
uBorderWidth: ValueCell.create(clamp(props.borderWidth / 2, 0, 0.5)), uBorderWidth: ValueCell.create(clamp(props.borderWidth / 2, 0, 0.5)),
uBorderColor: ValueCell.create(Color.toArrayNormalized(props.borderColor, Vec3.zero(), 0)), uBorderColor: ValueCell.create(Color.toArrayNormalized(props.borderColor, Vec3.zero(), 0)),
......
...@@ -34,6 +34,7 @@ function textRepr() { ...@@ -34,6 +34,7 @@ function textRepr() {
attachment: 'middle-center', attachment: 'middle-center',
fontSize: 96, fontSize: 96,
fontWeight: 'bold', fontWeight: 'bold',
background: true
} }
const textBuilder = TextBuilder.create(props, 1, 1) const textBuilder = TextBuilder.create(props, 1, 1)
...@@ -53,12 +54,13 @@ function textRepr() { ...@@ -53,12 +54,13 @@ function textRepr() {
} }
function spheresRepr() { function spheresRepr() {
const spheresBuilder = SpheresBuilder.create(2, 1) const spheresBuilder = SpheresBuilder.create(1, 1)
spheresBuilder.add(0, 0, 0, 0)
spheresBuilder.add(5, 0, 0, 0) spheresBuilder.add(5, 0, 0, 0)
spheresBuilder.add(-4, 1, 0, 0) spheresBuilder.add(-4, 1, 0, 0)
const spheres = spheresBuilder.getSpheres() const spheres = spheresBuilder.getSpheres()
const values = Spheres.createValuesSimple(spheres, {}, Color(0xFF0000), 1) const values = Spheres.createValuesSimple(spheres, {}, Color(0xFF0000), 0.2)
const state = Geometry.createRenderableState() const state = Geometry.createRenderableState()
const renderObject = createSpheresRenderObject(values, state) const renderObject = createSpheresRenderObject(values, state)
console.log('spheres', renderObject) console.log('spheres', renderObject)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment