Преглед изворни кода

support background for text rendering

Alexander Rose пре 6 година
родитељ
комит
06f9578cc6

+ 6 - 2
src/mol-geo/geometry/text/font-atlas.ts

@@ -33,7 +33,10 @@ export const FontAtlasParams = {
 export type FontAtlasParams = typeof 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 {
     readonly props: Readonly<FontAtlasProps>
@@ -120,7 +123,8 @@ export class FontAtlas {
 
             this.mapped[char] = {
                 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) {

+ 22 - 21
src/mol-geo/geometry/text/text-builder.ts

@@ -32,11 +32,11 @@ export namespace TextBuilder {
         const { attachment, background, backgroundMargin } = p
 
         const fontAtlas = getFontAtlas(p)
-        const { lineHeight } = fontAtlas
-
-        const margin = (lineHeight * backgroundMargin * 0.1) - 10
-        const outline = fontAtlas.buffer
-        console.log('margin', margin)
+        const margin = (1 / 2.5) * backgroundMargin
+        const outline = fontAtlas.buffer / fontAtlas.lineHeight
+        // console.log('margin', margin)
+        // console.log('attachment', attachment)
+        // console.log('background', background)
 
         return {
             add: (str: string, x: number, y: number, z: number, group: number) => {
@@ -46,15 +46,15 @@ export namespace TextBuilder {
                 // calculate width
                 for (let iChar = 0; iChar < nChar; ++iChar) {
                     const c = fontAtlas.get(str[iChar])
-                    xadvance += c.w - 2 * outline
+                    xadvance += c.nw - 2 * outline
                 }
 
                 // attachment
                 let yShift: number, xShift: number
                 if (attachment.startsWith('top')) {
-                    yShift = lineHeight / 1.25
+                    yShift = 1 / 1.25
                 } else if (attachment.startsWith('middle')) {
-                    yShift = lineHeight / 2.5
+                    yShift = 1 / 2.5
                 } else {
                     yShift = 0  // "bottom"
                 }
@@ -65,19 +65,17 @@ export namespace TextBuilder {
                 } else {
                     xShift = 0  // "left"
                 }
-                xShift += outline
-                yShift += outline
 
                 // background
                 if (background) {
-                    ChunkedArray.add2(mappings, -lineHeight / 6 - xShift - margin, lineHeight - yShift + margin)
-                    ChunkedArray.add2(mappings, -lineHeight / 6 - xShift - margin, 0 - yShift - margin)
-                    ChunkedArray.add2(mappings, xadvance + lineHeight / 6 - xShift + 2 * outline + margin, lineHeight - yShift + margin)
-                    ChunkedArray.add2(mappings, xadvance + lineHeight / 6 - xShift + 2 * outline + margin, 0 - yShift - margin)
+                    ChunkedArray.add2(mappings, -xadvance + xShift - margin - 0.1, yShift + margin) // top left
+                    ChunkedArray.add2(mappings, -xadvance + xShift - margin - 0.1, -yShift - margin) // bottom left
+                    ChunkedArray.add2(mappings, xadvance - xShift + margin + 0.1, yShift + margin) // top right
+                    ChunkedArray.add2(mappings, xadvance - xShift + margin + 0.1, -yShift - margin) // bottom right
 
                     const offset = centers.elementCount
                     for (let i = 0; i < 4; ++i) {
-                        ChunkedArray.add2(tcoords, 0, 10)
+                        ChunkedArray.add2(tcoords, 10, 10)
                         ChunkedArray.add3(centers, x, y, z);
                         ChunkedArray.add(groups, group);
                     }
@@ -85,15 +83,17 @@ export namespace TextBuilder {
                     ChunkedArray.add3(indices, offset + quadIndices[3], offset + quadIndices[4], offset + quadIndices[5])
                 }
 
+                xShift += outline
+                yShift += outline
                 xadvance = 0
 
                 for (let iChar = 0; iChar < nChar; ++iChar) {
                     const c = fontAtlas.get(str[iChar])
 
-                    ChunkedArray.add2(mappings, xadvance - xShift, c.h - yShift) // top left
-                    ChunkedArray.add2(mappings, xadvance - xShift, 0 - yShift) // bottom left
-                    ChunkedArray.add2(mappings, xadvance + c.w - xShift, c.h - yShift) // top right
-                    ChunkedArray.add2(mappings, xadvance + c.w - xShift, 0 - yShift) // bottom right
+                    ChunkedArray.add2(mappings, xadvance - xShift, c.nh - yShift) // top left
+                    ChunkedArray.add2(mappings, xadvance - xShift, -yShift) // bottom left
+                    ChunkedArray.add2(mappings, xadvance + c.nw - xShift, c.nh - yShift) // top right
+                    ChunkedArray.add2(mappings, xadvance + c.nw - xShift, -yShift) // bottom right
 
                     const texWidth = fontAtlas.texture.width
                     const texHeight = fontAtlas.texture.height
@@ -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 + c.h) / texHeight) // bottom right
 
-                    xadvance += c.w - 2 * outline
+                    xadvance += c.nw - 2 * outline
 
                     const offset = centers.elementCount
                     for (let i = 0; i < 4; ++i) {
@@ -120,10 +120,11 @@ export namespace TextBuilder {
                 const ib = ChunkedArray.compact(indices, true) as Uint32Array
                 const gb = ChunkedArray.compact(groups, true) as Float32Array
                 const tb = ChunkedArray.compact(tcoords, true) as Float32Array
+                const ft = fontAtlas.texture
                 return {
                     kind: 'text',
                     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),
                     mappingBuffer: text ? ValueCell.update(text.centerBuffer, mb) : ValueCell.create(mb),
                     indexBuffer: text ? ValueCell.update(text.indexBuffer, ib) : ValueCell.create(ib),

+ 12 - 13
src/mol-geo/geometry/text/text.ts

@@ -18,11 +18,11 @@ import { NullLocation } from 'mol-model/location';
 import { UniformColorTheme } from 'mol-theme/color/uniform';
 import { UniformSizeTheme } from 'mol-theme/size/uniform';
 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 { Color } from 'mol-util/color';
 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 { clamp } from 'mol-math/interpolate';
 
@@ -35,7 +35,7 @@ export interface Text {
     /** Number of characters in the text */
     readonly charCount: number,
     /** Font Atlas */
-    readonly fontAtlas: FontAtlas,
+    readonly fontTexture: ValueCell<TextureImage<Uint8Array>>,
 
     /** Center buffer as array of xyz values wrapped in a value cell */
     readonly centerBuffer: ValueCell<Float32Array>,
@@ -56,10 +56,11 @@ export namespace Text {
         const ib = text ? text.indexBuffer.ref.value : new Uint32Array(0)
         const gb = text ? text.groupBuffer.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 {
             kind: 'text',
             charCount: 0,
-            fontAtlas: getFontAtlas({}),
+            fontTexture: text ? ValueCell.update(text.fontTexture, ft) : ValueCell.create(ft),
             centerBuffer: text ? ValueCell.update(text.centerBuffer, cb) : ValueCell.create(cb),
             mappingBuffer: text ? ValueCell.update(text.mappingBuffer, mb) : ValueCell.create(mb),
             indexBuffer: text ? ValueCell.update(text.indexBuffer, ib) : ValueCell.create(ib),
@@ -75,13 +76,13 @@ export namespace Text {
 
         borderWidth: PD.Numeric(0, { min: 0, max: 1, step: 0.01 }),
         borderColor: PD.Color(ColorNames.grey),
-        offsetX: PD.Numeric(1, { min: 0, max: 10, step: 0.1 }),
-        offsetY: PD.Numeric(1, { min: 0, max: 10, step: 0.1 }),
-        offsetZ: PD.Numeric(1, { min: 0, max: 10, step: 0.1 }),
+        offsetX: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }),
+        offsetY: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }),
+        offsetZ: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }),
         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),
-        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][]),
     }
@@ -105,8 +106,6 @@ export namespace Text {
             transform.aTransform.ref.value, instanceCount, padding
         )
 
-        console.log(props.sizeFactor, text.fontAtlas.lineHeight, props.fontSize)
-
         return {
             aPosition: text.centerBuffer,
             aMapping: text.mappingBuffer,
@@ -120,11 +119,11 @@ export namespace Text {
             ...transform,
 
             aTexCoord: text.tcoordBuffer,
-            tFont: ValueCell.create(text.fontAtlas.texture),
+            tFont: text.fontTexture,
             padding: ValueCell.create(padding),
 
             ...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)),
             uBorderColor: ValueCell.create(Color.toArrayNormalized(props.borderColor, Vec3.zero(), 0)),

+ 4 - 2
src/tests/browser/render-text.ts

@@ -34,6 +34,7 @@ function textRepr() {
         attachment: 'middle-center',
         fontSize: 96,
         fontWeight: 'bold',
+        background: true
     }
 
     const textBuilder = TextBuilder.create(props, 1, 1)
@@ -53,12 +54,13 @@ function textRepr() {
 }
 
 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(-4, 1, 0, 0)
     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 renderObject = createSpheresRenderObject(values, state)
     console.log('spheres', renderObject)