From 5058d628765c20b0c607da31e235d1d765085c9b Mon Sep 17 00:00:00 2001 From: Dany LE Date: Thu, 24 Mar 2022 22:48:41 +0100 Subject: [PATCH] wip: rework on text rendering (performance is still degraded) --- Diya/Diya2DNode.class.st | 16 --- Diya/Diya2DPrimShape.class.st | 13 +++ Diya/DiyaButton.class.st | 49 +++++++++ Diya/DiyaDefaultStyle.class.st | 4 +- Diya/DiyaExampleApp.class.st | 20 +++- Diya/DiyaFontIcon.class.st | 9 +- Diya/DiyaLabel.class.st | 50 ++++++++- Diya/DiyaRectangle.class.st | 11 +- Diya/DiyaText.class.st | 178 ++++++++++++++++++++++++--------- Diya/DiyaWidget.class.st | 27 ++--- 10 files changed, 277 insertions(+), 100 deletions(-) diff --git a/Diya/Diya2DNode.class.st b/Diya/Diya2DNode.class.st index c843bef..5c6c828 100644 --- a/Diya/Diya2DNode.class.st +++ b/Diya/Diya2DNode.class.st @@ -19,16 +19,6 @@ Diya2DNode >> boundingBox [ ^rec ] -{ #category : #accessing } -Diya2DNode >> color [ - ^ self style get: #color. -] - -{ #category : #accessing } -Diya2DNode >> color: anObject [ - style set:#color value: anObject -] - { #category : #accessing } Diya2DNode >> draw [ @@ -83,12 +73,6 @@ Diya2DNode >> recFromBuffer [ ^ Rectangle origin: minX@minY corner: maxX @ maxY ] -{ #category : #initialization } -Diya2DNode >> setUpShader [ - super setUpShader. - shader setUniform: #u_color value: self color asGL4FArray. -] - { #category : #accessing } Diya2DNode >> updateTF [ tf := Array2D identity:3. diff --git a/Diya/Diya2DPrimShape.class.st b/Diya/Diya2DPrimShape.class.st index 72bb837..d03e9ab 100644 --- a/Diya/Diya2DPrimShape.class.st +++ b/Diya/Diya2DPrimShape.class.st @@ -34,6 +34,18 @@ Diya2DPrimShape >> boundingBox [ ^ bbox applyTf: self tf. ] +{ #category : #accessing } +Diya2DPrimShape >> color [ + self texture ifNotNil: [ ^ self style get: #color. ]. + ^ self style get: #bgcolor. +] + +{ #category : #accessing } +Diya2DPrimShape >> color: value [ + self texture ifNotNil: [ ^ self style set: #color value: value. ]. + ^ self style set: #bgcolor value: value. +] + { #category : #initialization } Diya2DPrimShape >> draw [ vbuffer ifNil: [ ^self ]. @@ -98,6 +110,7 @@ Diya2DPrimShape >> inner: aPoint [ Diya2DPrimShape >> setUpShader [ super setUpShader. self shader + setUniform: #u_color value: self color asGL4FArray; setUniform: #u_texture_type value: (self texture ifNil: [ 0 ] ifNotNil:[self texture format]). ] diff --git a/Diya/DiyaButton.class.st b/Diya/DiyaButton.class.st index 693b3d3..e54dfae 100644 --- a/Diya/DiyaButton.class.st +++ b/Diya/DiyaButton.class.st @@ -1,5 +1,54 @@ Class { #name : #DiyaButton, #superclass : #DiyaWidget, + #instVars : [ + 'label', + 'rec' + ], #category : #'Diya-Widgets' } + +{ #category : #accessing } +DiyaButton class >> text: string [ + ^ self new text: string; yourself +] + +{ #category : #accessing } +DiyaButton >> icon: id [ + label icon: id. + label updateLayout. +] + +{ #category : #accessing } +DiyaButton >> iconSize: size [ + label iconSize: size. +] + +{ #category : #initialization } +DiyaButton >> initialize [ + super initialize. + style + set:#textAlign value: #center; + set:#textVAlign value: #middle. + rec := self addNode: (DiyaRectangle new). + label := self addNode: (DiyaLabel new). + label txt + wordWrap: false. +] + +{ #category : #accessing } +DiyaButton >> label [ + ^ label +] + +{ #category : #accessing } +DiyaButton >> text: string [ + label txt: string. +] + +{ #category : #accessing } +DiyaButton >> updateLayout [ + rec extent: self extent. + label position: 0@(self extent y). + label extent: self extent. +] diff --git a/Diya/DiyaDefaultStyle.class.st b/Diya/DiyaDefaultStyle.class.st index f995a31..396507d 100644 --- a/Diya/DiyaDefaultStyle.class.st +++ b/Diya/DiyaDefaultStyle.class.st @@ -14,5 +14,7 @@ DiyaDefaultStyle >> initialize [ self set: #fontFamily value: DiyaFontManager uniqueInstance defaultFamily. self set: #fontStyle value: DiyaFontManager uniqueInstance defaultStyle. self set: #borderColor value: (Color r: 0.051 g: 0.051 b: 0.051). - self set: #bgcolor2 value: (Color r: 0.1529 g: 0.1529 b: 0.1529) + self set: #bgcolor2 value: (Color r: 0.1529 g: 0.1529 b: 0.1529). + self set: #textAlign value: #left. + self set: #textVAlign value: #top ] diff --git a/Diya/DiyaExampleApp.class.st b/Diya/DiyaExampleApp.class.st index 7f3cae5..aa95d35 100644 --- a/Diya/DiyaExampleApp.class.st +++ b/Diya/DiyaExampleApp.class.st @@ -16,8 +16,8 @@ DiyaExampleApp >> main [ { #category : #accessing } DiyaExampleApp >> setup [ - |node node1 ell label icon| - label := root addNode: (DiyaLabel new) at: 10@30. + |node node1 ell label icon button| + label := root addNode: (DiyaLabel new) at: 10@40. label extent: 250@30. label color: Color orange. label icon: 16rF254. @@ -34,15 +34,20 @@ DiyaExampleApp >> setup [ "node borderWidth: 3.0." node extent:200@200. - node := root addNode: (DiyaText data: String loremIpsum) at: 10@400. + node := root addNode: (DiyaRectangle new) at: 10@80. + node extent: 240@320. + + "node := root addNode: (DiyaText data: String loremIpsum) at: 10@400. node extent: 240@320. node wordWrap: true. + node fontSize: 16. + node align: #center." node := root addNode: (DiyaLine from: 10@620 to: 200@635). node color: (Color red). node borderWidth: 2.0. - ell := root addNode: (DiyaEllipse rx:150 ry: 100) at: 320@300. + ell := root addNode: (DiyaEllipse rx:100 ry: 70) at: 340@300. ell borderColor: Color red. ell color: Color white. ell rotation: Float pi / 6.0. @@ -58,8 +63,13 @@ DiyaExampleApp >> setup [ node textureNamed: 'mrsang.png'. node borderWidth: 3.0. - icon := root addNode: (DiyaFontIcon data: #(16rF101 16rF155 16rF185 16rF21B 16rF298 16rF254)) at: 10@10. + icon := root addNode: (DiyaFontIcon data: #(16rF101 16rF155 16rF185 16rF21B 16rF298 16rF254)) at: 10@24. icon fontSize: 24. icon color: (Color r: 209/255 g: 66/255 b:245/255 ). + + button := root addNode: (DiyaButton text: 'Click me !') at: 160@10. + button extent: 200@40. + button icon:16rF185. + button iconSize: 24. ^ root ] diff --git a/Diya/DiyaFontIcon.class.st b/Diya/DiyaFontIcon.class.st index d9e62ab..4a1d771 100644 --- a/Diya/DiyaFontIcon.class.st +++ b/Diya/DiyaFontIcon.class.st @@ -15,12 +15,13 @@ DiyaFontIcon >> data: code [ { #category : #initialization } DiyaFontIcon >> drawText [ - |index offset tex| + |index offset tex glyph | index := 1. tex := self texture. - offset := 0@(self fontSize). - 1 to: data size do: [ :i| - (self getCharsVerticesAt:i offset: offset on: tex) do: [ + offset := (self alignLine: self fontSize)@(self valignText: self fontSize). + data do: [ :c| + glyph := tex getGlyph: c asInteger. + (self getCharsVerticesFrom: glyph offset: offset cellh: tex cellh) do: [ :e| vbuffer at: index put:e. index := index + 1 ]. diff --git a/Diya/DiyaLabel.class.st b/Diya/DiyaLabel.class.st index ad3793b..0a48263 100644 --- a/Diya/DiyaLabel.class.st +++ b/Diya/DiyaLabel.class.st @@ -8,6 +8,20 @@ Class { #category : #'Diya-Widgets' } +{ #category : #accessing } +DiyaLabel >> fontSize [ + ^txt fontSize. + +] + +{ #category : #accessing } +DiyaLabel >> fontSize: value [ + txt fontSize: value. + icon ifNotNil: [ icon fontSize: value ]. + "dirty := true." + +] + { #category : #accessing } DiyaLabel >> icon [ ^ icon @@ -16,19 +30,43 @@ DiyaLabel >> icon [ { #category : #accessing } DiyaLabel >> icon: anObject [ icon := nil. - anObject isNumber ifTrue: [ icon := self addNode: (DiyaFontIcon data: anObject) ]. + anObject isNumber ifTrue: [ + icon := self addNode: (DiyaFontIcon data: anObject). + icon align: #left]. anObject isString ifTrue: [ icon := self addNode: (DiyaImageView from: anObject)]. icon ifNil: [ ^ DiyaCoreAPIError signal: 'Invalid icon identification']. dirty := true. ] +{ #category : #accessing } +DiyaLabel >> iconPosition: offset [ + |xpos| + txt splitLines. + txt lines ifEmpty: [ ^0@0 ]. + xpos := txt alignLine: txt lines first key. + ^xpos@0 +] + +{ #category : #accessing } +DiyaLabel >> iconSize [ + icon ifNil: [ ^0 ]. + ^icon fontSize. + +] + +{ #category : #accessing } +DiyaLabel >> iconSize: v [ + icon ifNil: [ ^self ]. + icon fontSize: v. + +] + { #category : #initialization } DiyaLabel >> initialize [ super initialize. txt := self addNode:(DiyaText data: ''). icon := nil. self extent: 0@0. - "style := DiyaDefaultStyle uniqueInstance." ] { #category : #accessing } @@ -46,12 +84,14 @@ DiyaLabel >> txt: anObject [ DiyaLabel >> updateLayout [ |offset isize| offset := 0. - isize := style get: #fontSize. icon ifNotNil: [ + isize := icon fontSize. offset := isize + (isize >> 1). - icon position: 0 @ (extent y - isize) + icon extent:offset @ (extent y). ]. txt extent: (extent x - offset) @ (extent y). - txt position: offset @ (extent y) + txt position: offset @ 0. + icon ifNil: [ ^self ]. + icon position: (self iconPosition: offset). ] diff --git a/Diya/DiyaRectangle.class.st b/Diya/DiyaRectangle.class.st index 53eef21..ea2acf6 100644 --- a/Diya/DiyaRectangle.class.st +++ b/Diya/DiyaRectangle.class.st @@ -16,10 +16,7 @@ DiyaRectangle class >> size: size shader:s [ { #category : #initialization } DiyaRectangle >> drawLines [ - self drawLineAt: 0. - self drawLineAt: 1. - self drawLineAt: 3. - self drawLineAt: 4. + OpenGL drawArrays: GL_LINE_LOOP first:0 count: (vbuffer size >> 2). ] @@ -34,8 +31,9 @@ DiyaRectangle >> initialize [ super initialize. self extent:10@10. translation := nil. - vbuffer := FFIExternalArray externalNewType: GLfloat size:24. + vbuffer := FFIExternalArray externalNewType: GLfloat size:16. vbuffer autoRelease. + type := GL_QUADS. ] { #category : #accessing } @@ -46,10 +44,7 @@ DiyaRectangle >> update [ 0.0. extent y. 0.0. 0.0. 0. 0. 0.0. 1.0. extent x. 0.0. 1.0. 1.0. - - extent x. 0.0. 1.0. 1.0. extent x. extent y. 1.0. 0.0. - 0.0. extent y. 0.0. 0.0. } doWithIndex: [:e :i| vbuffer at: i put: e]. ^true ] diff --git a/Diya/DiyaText.class.st b/Diya/DiyaText.class.st index ce84674..265910a 100644 --- a/Diya/DiyaText.class.st +++ b/Diya/DiyaText.class.st @@ -5,7 +5,8 @@ Class { 'data', 'wrap', 'texheight', - 'font' + 'font', + 'lines' ], #pools : [ 'FT2Types' @@ -23,6 +24,35 @@ DiyaText class >> data: string shader: s [ ^ (self with:s) data: string; yourself ] +{ #category : #'menu messages' } +DiyaText >> align [ + ^ self style get: #textAlign +] + +{ #category : #'menu messages' } +DiyaText >> align: v [ + self style set: #textAlign value: v. + self formatText +] + +{ #category : #accessing } +DiyaText >> alignLine:w [ + self align = #center ifTrue:[^ 0 max:((self extent x - w) / 2.0 ) asFloat]. + self align = #right ifTrue:[^ 0 max: self extent x - w]. + ^0 +] + +{ #category : #initialization } +DiyaText >> allocMemory [ + vbuffer ifNotNil: [ + vbuffer size >= data size + ifTrue: [^self] + ifFalse:[vbuffer free] + ]. + vbuffer := FFIExternalArray externalNewType: GLfloat size: data size * 16. + vbuffer autoRelease. +] + { #category : #accessing } DiyaText >> data [ ^ data @@ -46,23 +76,8 @@ DiyaText >> drawLines [ { #category : #accessing } DiyaText >> drawText [ - |vertices index tex2D offset lbdelta| - index := 1. - offset := 0@0. - tex2D := self texture. - lbdelta := self getLinebreakIndices: (self extent x / tex2D meanww) asInteger. - 1 to: data size do: [ :i| - vertices := self getCharsVerticesAt:i offset: offset on: tex2D. - vertices do: [ - :e| vbuffer at: index put:e. - index := index + 1. - ]. - (offset x > self extent x and: wrap not) ifTrue: [ ^self ]. - ((lbdelta includes: i + 1) and: wrap) ifTrue: [ - offset setX: 0.0 setY: (offset y )- (tex2D linespace). - (offset y negated > self extent y) ifTrue: [ ^self ]. - ]. - ]. + self splitLines. + self formatText . ] { #category : #accessing } @@ -81,8 +96,8 @@ DiyaText >> fontName: name style: face size: size [ name ifNotNil: [style set:#fontFamily value: name]. face ifNotNil: [style set: #fontStyle value:face]. style set: #fontSize value: size. - font := nil. dirty := true. + self initTexture ] { #category : #accessing } @@ -101,16 +116,31 @@ DiyaText >> fontStyle [ ] { #category : #accessing } -DiyaText >> getCharsVerticesAt:i offset: offset on: tex2D [ - |x y w h glyph gsize c texcoord| - c := (data at:i) asInteger. - glyph := tex2D getGlyph: c. - gsize := glyph extent. - ((offset x > self extent x) and: (gsize x > 0)) ifTrue:[ - wrap ifFalse: [ ^ { } ]. +DiyaText >> formatText [ + |offset index line| + lines ifNil: [^self]. + offset := 0@(self valignText: (texture linespace) * (lines size)). + index := 1. + lines do:[:assoc| + line := assoc value. + offset setX: (self alignLine: assoc key) setY: offset y. + line do:[:g| + (self getCharsVerticesFrom: g offset: offset cellh: texture cellh) do:[:v| + vbuffer at: index put:v. + index := index + 1. + ] + ]. + offset setX: 0.0 setY: (offset y )- (texture linespace) ]. + +] + +{ #category : #accessing } +DiyaText >> getCharsVerticesFrom:glyph offset: offset cellh: cellh [ + |x y w h gsize texcoord| + gsize := glyph extent. x := offset x + (glyph bearing x). - y := offset y - (tex2D cellh). + y := offset y - cellh. w := (gsize x). h := (gsize y). texcoord := glyph texcoord. @@ -118,23 +148,35 @@ DiyaText >> getCharsVerticesAt:i offset: offset on: tex2D [ ^{x. y + h. texcoord origin x. texcoord origin y. x. y. texcoord origin x. texcoord corner y. x + w. y. texcoord corner x. texcoord corner y. - x. y + h. texcoord origin x. texcoord origin y. - x + w. y. texcoord corner x. texcoord corner y. + "x. y + h. texcoord origin x. texcoord origin y. + x + w. y. texcoord corner x. texcoord corner y." x + w. y + h. texcoord corner x. texcoord origin y. }. ] { #category : #accessing } -DiyaText >> getLinebreakIndices: delta [ - |indices idx| - indices := Set new. - idx := delta + 1. - [ - idx < data size - ] whileTrue: [ - indices add: (self lastSeparatorFrom: idx) + 1. - idx := idx + delta. - ]. - ^indices +DiyaText >> getLineAt: index to: line with: tex2D [ + | glyph ret w | + w := 0. + index to: data size do:[ :i| + glyph := tex2D getGlyph: (data at:i) asInteger. + (w + (glyph advance x)) >= (self extent x) ifTrue:[ + wrap ifFalse: [ ^ i @ w]. + ret := self lastSeparatorFrom: i. + ret to: i - 1 do:[:j| + w := w - (line removeLast advance x)]. + ^ (ret+1)@w + ] ifFalse:[ + w := w + (glyph advance x). + line add: glyph. + ]. + ]. + ^ (data size + 1) @ w +] + +{ #category : #initialization } +DiyaText >> initTexture [ + font:= DiyaFontManager uniqueInstance style: self fontStyle from: self fontName. + texture := font textureOf: self fontSize. ] { #category : #initialization } @@ -143,7 +185,8 @@ DiyaText >> initialize [ data := nil. wrap := false. texheight := 0. - style set: #border value: 0 + style set: #border value: 0. + type := GL_QUADS. ] { #category : #'as yet unclassified' } @@ -154,29 +197,66 @@ DiyaText >> lastSeparatorFrom: index [ ^ 0 ] +{ #category : #accessing } +DiyaText >> lines [ + ^ lines +] + +{ #category : #accessing } +DiyaText >> splitLines [ + |line ret tex2D| + ret := 1@0. + tex2D := self texture. + lines := OrderedCollection new. + [ + line := OrderedCollection new. + ret := self getLineAt: ret x to: line with: tex2D. + lines add: ((ret y) -> line). + (ret x < data size) and: wrap + ] whileTrue. +] + { #category : #accessing } DiyaText >> texture [ - | tex| - font:= font ifNil: [ DiyaFontManager uniqueInstance style: self fontStyle from: self fontName ]. - tex := font textureOf: self fontSize. - texheight = tex height ifFalse: [ - texheight := tex height. + texture ifNil: [ self initTexture ]. + texheight = texture height ifFalse: [ + texheight := texture height. self update. dirty := false. ]. - ^tex + ^texture ] { #category : #initialization } DiyaText >> update [ - bbox ifNil: [ ^false ]. + bbox ifNil: [ ^true ]. + data ifNil:[^true]. + data ifEmpty:[^true]. vbuffer ifNotNil: [vbuffer free]. - vbuffer := FFIExternalArray externalNewType: GLfloat size: data size * 24. + vbuffer := FFIExternalArray externalNewType: GLfloat size: data size * 16. vbuffer autoRelease. self drawText. ^true ] +{ #category : #'menu messages' } +DiyaText >> valign [ + ^ self style get: #textVAlign +] + +{ #category : #'menu messages' } +DiyaText >> valign: v [ + self style set: #textVAlign value: v. + self formatText. +] + +{ #category : #accessing } +DiyaText >> valignText:h [ + self valign = #middle ifTrue:[^ (0 max:((self extent y - h) / 2 ) asFloat) negated]. + self valign = #bottom ifTrue:[^ (0 max:(self extent y - h )) negated]. + ^0 +] + { #category : #initialization } DiyaText >> wordWrap: aBool [ wrap := aBool. diff --git a/Diya/DiyaWidget.class.st b/Diya/DiyaWidget.class.st index 49a9832..5e6edb5 100644 --- a/Diya/DiyaWidget.class.st +++ b/Diya/DiyaWidget.class.st @@ -12,6 +12,21 @@ DiyaWidget class >> fromStyle: aStyle [ ^self new style: aStyle; yourself ] +{ #category : #accessing } +DiyaWidget >> color [ + ^style get: #color +] + +{ #category : #accessing } +DiyaWidget >> color: value [ + style set: #color value: value +] + +{ #category : #geometry } +DiyaWidget >> extent [ + ^extent +] + { #category : #geometry } DiyaWidget >> extent: size [ extent := size. @@ -21,18 +36,6 @@ DiyaWidget >> extent: size [ { #category : #initialization } DiyaWidget >> initialize [ super initialize. - self style: DiyaDefaultStyle new. -] - -{ #category : #accessing } -DiyaWidget >> style [ - ^ style -] - -{ #category : #accessing } -DiyaWidget >> style: anObject [ - style := anObject. - dirty := true ] { #category : #accessing }