From 3c00e1d181cde5c536e291a4a661ee75b4ce55df Mon Sep 17 00:00:00 2001 From: Dany LE Date: Mon, 15 Aug 2022 12:28:09 +0200 Subject: [PATCH] refactory code, support inline style, improve text rendering --- Diya/DiyaApplicationLauncher.class.st | 74 +++++----- Diya/DiyaApplicationModel.class.st | 33 +++-- Diya/DiyaBaseApplication.class.st | 4 +- Diya/DiyaBoot.class.st | 9 +- Diya/DiyaDefaultAppLoader.class.st | 24 ++++ Diya/DiyaExampleApp.class.st | 200 +++++++++++++------------- Diya/DiyaLoader.class.st | 54 +++++++ Diya/DiyaNode.class.st | 12 +- Diya/DiyaRendererContext.class.st | 2 +- Diya/DiyaText.class.st | 11 +- 10 files changed, 265 insertions(+), 158 deletions(-) create mode 100644 Diya/DiyaDefaultAppLoader.class.st create mode 100644 Diya/DiyaLoader.class.st diff --git a/Diya/DiyaApplicationLauncher.class.st b/Diya/DiyaApplicationLauncher.class.st index 35428f6..373c6ae 100644 --- a/Diya/DiyaApplicationLauncher.class.st +++ b/Diya/DiyaApplicationLauncher.class.st @@ -4,7 +4,6 @@ Class { #instVars : [ 'currapp', 'txtFPS', - 'event', 'running' ], #category : #'Diya-Applications' @@ -12,17 +11,17 @@ Class { { #category : #initialization } DiyaApplicationLauncher >> appNode [ - ^root children first + ^node children first ] { #category : #initialization } DiyaApplicationLauncher >> bindGlobalEvent [ |pointer | - pointer := root addNode: (DiyaCircle r: 10) at: 200@200. + pointer := node addNode: (DiyaCircle r: 10) at: 200@200. pointer styleName: #pointer. - root on: #keydown do:[:e| self stdlog: 'keydown...'. running := false.]. - root on: #quit do: [:e| running := false]. - root on: #(fingerdown fingermotion mousemotion) do:[:e| + node on: #keydown do:[:e| self stdlog: 'keydown...'. running := false.]. + node on: #quit do: [:e| running := false]. + node on: #(fingerdown fingermotion mousemotion) do:[:e| pointer position: e mapped worldPosition. DiyaRenderer mouse: (e mapped x) @ (e mapped y). ]. @@ -33,10 +32,15 @@ DiyaApplicationLauncher >> defaultApplication [ ^DiyaExampleApp ] +{ #category : #initialization } +DiyaApplicationLauncher >> initLoader [ + +] + { #category : #initialization } DiyaApplicationLauncher >> initialize [ super initialize. - root := DiyaRenderer root. + node := DiyaRenderer root. currapp := nil. ] @@ -44,42 +48,22 @@ DiyaApplicationLauncher >> initialize [ DiyaApplicationLauncher >> launch: app [ currapp ifNotNil: [ currapp quit. - root empty. + node empty. ]. currapp := app uniqueInstance. self context assets: currapp am. - [ - self stdlog: 'Loading application'. - currapp root visibility: false. - currapp setup. - currapp root forceReload. - self appNode addNode: currapp root. - currapp root visibility: true. + self appNode addNode: currapp loader node. + currapp onloaded:[ + self appNode empty. + currapp node visibility: false. + self appNode addNode: currapp node. + currapp node visibility: true. self stdlog: 'Application LOADED'. - ] fork. -] - -{ #category : #initialization } -DiyaApplicationLauncher >> main [ - | fps delta| - delta := DiyaSystemClock delta. - fps := DiyaSystemSettings maxFPS. - delta = 0 ifFalse:[ fps := (1000/ delta) asInteger]. - txtFPS data: ('FPS:', fps asString). - [(SDL2 pollEvent: event) > 0] whileTrue: [ - root trigger: (DiyaEvent from: event mapped). ]. - currapp ifNotNil: [currapp main.]. -] - -{ #category : #accessing } -DiyaApplicationLauncher >> running [ - ^ running ] { #category : #initialization } -DiyaApplicationLauncher >> setup [ - event := SDL_Event new. +DiyaApplicationLauncher >> onloaded: aBlock [ DiyaUIThemesManager uniqueInstance currentTheme define: #fps_text styles: { #color -> Color red. @@ -91,11 +75,27 @@ DiyaApplicationLauncher >> setup [ #bgColor -> Color orange. #border -> 3 }. - root addNode: (DiyaCompositeNode new) at: 0@0. - txtFPS := root addNode:(DiyaText data: '') at: ( self context resolution x - 80)@(self context resolution y - 40). + node addNode: (DiyaCompositeNode new) at: 0@0. + txtFPS := node addNode:(DiyaText data: '') at: ( self context resolution x - 80)@(self context resolution y - 40). + node addNode: (DiyaTimerNode timeout: 0 do: [:n| self updateFPS ] ). txtFPS extent: 80@40. txtFPS styleName: #fps_text. self bindGlobalEvent. running := true. self launch: self defaultApplication. + aBlock value. +] + +{ #category : #accessing } +DiyaApplicationLauncher >> running [ + ^ running +] + +{ #category : #initialization } +DiyaApplicationLauncher >> updateFPS [ + | fps delta| + delta := DiyaSystemClock delta. + fps := DiyaSystemSettings maxFPS. + delta = 0 ifFalse:[ fps := (1000/ delta) asInteger]. + txtFPS data: ('FPS:', fps asString). ] diff --git a/Diya/DiyaApplicationModel.class.st b/Diya/DiyaApplicationModel.class.st index ddbe01c..13d502e 100644 --- a/Diya/DiyaApplicationModel.class.st +++ b/Diya/DiyaApplicationModel.class.st @@ -2,8 +2,9 @@ Class { #name : #DiyaApplicationModel, #superclass : #DiyaSingleton, #instVars : [ - 'root', - 'am' + 'node', + 'am', + 'loader' ], #category : #'Diya-Applications' } @@ -23,13 +24,29 @@ DiyaApplicationModel >> context [ ^DiyaRenderer ] +{ #category : #initialization } +DiyaApplicationModel >> initLoader [ + self subclassResponsibility +] + { #category : #initialization } DiyaApplicationModel >> initialize [ super initialize. + self initLoader. ] { #category : #accessing } -DiyaApplicationModel >> main [ +DiyaApplicationModel >> loader [ + ^ loader +] + +{ #category : #accessing } +DiyaApplicationModel >> node [ + ^ node +] + +{ #category : #accessing } +DiyaApplicationModel >> onloaded: aBlock [ self subclassResponsibility ] @@ -37,13 +54,3 @@ DiyaApplicationModel >> main [ DiyaApplicationModel >> quit [ self cleanup ] - -{ #category : #accessing } -DiyaApplicationModel >> root [ - ^ root -] - -{ #category : #accessing } -DiyaApplicationModel >> setup [ - self subclassResponsibility -] diff --git a/Diya/DiyaBaseApplication.class.st b/Diya/DiyaBaseApplication.class.st index 13789c6..4963647 100644 --- a/Diya/DiyaBaseApplication.class.st +++ b/Diya/DiyaBaseApplication.class.st @@ -7,7 +7,7 @@ Class { { #category : #initialization } DiyaBaseApplication >> initialize [ super initialize. - root := DiyaCompositeNode new. - root styleName: #global. + node := DiyaCompositeNode new. + node styleName: #global. am := AssetManager new. ] diff --git a/Diya/DiyaBoot.class.st b/Diya/DiyaBoot.class.st index 40bc337..44d89bc 100644 --- a/Diya/DiyaBoot.class.st +++ b/Diya/DiyaBoot.class.st @@ -96,15 +96,18 @@ DiyaBoot >> initialize [ { #category : #events } DiyaBoot >> render [ - |launcher| + |launcher event| + event := SDL_Event new. launcher := DiyaApplicationLauncher uniqueInstance. - launcher setup. "Init the Open GL view port and enable 2D texture" OpenGL viewportX: 0 Y:0 W: display w H: display h. OpenGL enable: GL_TEXTURE_2D. + launcher onloaded: [self stdlog: 'Launcher loaded']. [ launcher running ] whileTrue: [ DiyaSystemClock tick. - launcher main. + [(SDL2 pollEvent: event) > 0] whileTrue: [ + DiyaRenderer root trigger: (DiyaEvent from: event mapped). + ]. DiyaRenderer render. SDL2 delay: (0 max: diff --git a/Diya/DiyaDefaultAppLoader.class.st b/Diya/DiyaDefaultAppLoader.class.st new file mode 100644 index 0000000..bcabee5 --- /dev/null +++ b/Diya/DiyaDefaultAppLoader.class.st @@ -0,0 +1,24 @@ +Class { + #name : #DiyaDefaultAppLoader, + #superclass : #DiyaLoader, + #instVars : [ + 'progress', + 'label' + ], + #category : #'Diya-Applications' +} + +{ #category : #initialization } +DiyaDefaultAppLoader >> init [ + progress := node addNode: (DiyaLoadingBar new) at: 20@50. + progress extent: 420 @ 20. + label := node addNode: (DiyaText new) at: 20@80. + label extent: 420 @ 20. + label inlineStyle: #xAlign value: #center +] + +{ #category : #scheduling } +DiyaDefaultAppLoader >> updateProgress: name percent: p [ + label data: name. + progress percent: p +] diff --git a/Diya/DiyaExampleApp.class.st b/Diya/DiyaExampleApp.class.st index c9daee5..e443c04 100644 --- a/Diya/DiyaExampleApp.class.st +++ b/Diya/DiyaExampleApp.class.st @@ -9,6 +9,98 @@ DiyaExampleApp >> cleanup [ ] +{ #category : #accessing } +DiyaExampleApp >> defineNodes [ + |node2 node1 img ell label icon button texture loading| + texture := DiyaImageTex new. + label := node addNode: (DiyaLabel new) at: 10@40. + label extent: 250@24. + label styleName:#text_icon_1. + label icon: 16rF254. + + node1 := node addNode: (DiyaRectangle size:100@150 shader: DiyaExampleShader uniqueInstance) at: 300 @ 40. + node1 rotation: 45. + node1 scale: 2.0@2.0. + node1 on: #(mousebuttondown fingerdown) do:[:e| + label txt: 'RECT ', (node1 local: e mapped worldPosition) asIntegerPoint asString]. + + img := node addNode: (DiyaImageView from:'mrsang.png') at: 10 @ 400. + img styleName: #image_view. + img extent:200@200. + node on: #(mousebuttondown fingerdown) do:[:e| + "change texture" + |p| + p := e mapped worldPosition. + label txt: 'Mouse ', p asIntegerPoint asString. + DiyaRenderer assets + addAsset:(texture fromDisplay: (Rectangle origin: ((p x - 100) @ (p y - 100)) extent: 200@200 ) as: 'capture'). + img textureNamed: 'capture'. + + ]. + + node2 := node addNode: (DiyaRectangle new) at: 10@80. + node2 styleName: #rect_view. + node2 extent: 240@320. + + node2 := node addNode: (DiyaText data: String loremIpsum) at: 10@80. + node2 extent: 240@320. + node2 wordWrap: true. + node2 styleName: #text_view. + + node2 := node addNode: (DiyaLine from: 10@10 to: 200@200). + node2 styleName: #line_view. + + ell := node addNode: (DiyaEllipse rx:100 ry: 70) at: 120@300. + ell scale: 1.2 @ 1.2. + ell styleName: #ell_view. + "ell rotation: 30." + ell textureNamed:'mrsang.png'. + ell addNode: (DiyaTimerNode timeout: 1000 / 6 do:[:n | + n parent rotation: n parent rotation + 10. + ] ). + ell on: #(mousebuttondown fingerdown) do:[:e| + label txt: 'Ellipse clicked', (ell local:e mapped worldPosition) asIntegerPoint asString]. + + node2 := node addNode: (DiyaConvexPolygon points:{0@40. 150@190. 200@20. 100@0}) at: 250@60. + node2 textureNamed: 'mrsang.png'. + node2 styleName: #poly_view. + + icon := node addNode: (DiyaFontIcon data: #(16rF101 16rF155 16rF185 16rF21B 16rF298 16rF254)) at: 240@500. + icon styleName: #text_icon_2. + + button := node addNode: (DiyaButton text: 'Click me !') at: 240@460. + icon := DiyaFontIcon data: 16rF130. + "icon := DiyaImageIcon from: 'mrsang.png'." + icon addNode:(DiyaTimerNode timeout: 1000 / 12 do:[:n | + n parent rotation: n parent rotation + 10 pivot: n parent extent / 2. + ] ). + button extent: 200@40. + button icon: icon "'mrsang.png'". + "button rotation: Float pi / 2.0." + button styleName: #button_view. + + loading := node addNode: (DiyaLoadingBar new) at: 240@550. + loading extent: 200 @ 20. + + loading addNode: (DiyaTimerNode timeout: 2000 do:[:n | + |p| + p := (n parent percent + 10). + p > 100 ifTrue:[ p := 0]. + n parent percent: p. + ] ). + + + loading := node addNode: (DiyaLoadingBar new) at: 240@580. + loading extent: 200 @ 20. + + loading addNode: (DiyaTimerNode timeout: 1000 do:[:n | + |p| + p := (n parent percent + 10). + p > 100 ifTrue:[ p := 0]. + n parent percent: p. + ] ). +] + { #category : #accessing } DiyaExampleApp >> defineStyleSheet [ |fmgr style| @@ -16,7 +108,7 @@ DiyaExampleApp >> defineStyleSheet [ #(16 18 24) do:[:fontSize| self stdlog: 'Init font size ', fontSize asString, ' of ', fmgr defaultFamily. style := fmgr style: fmgr defaultStyle from: fmgr defaultFamily. - style textureOf: fontSize. + (style textureOf: fontSize)" genPrintableASCII" . ]. DiyaUIThemesManager uniqueInstance currentTheme define: #text_icon_1 styles: { @@ -67,104 +159,18 @@ DiyaExampleApp >> defineStyleSheet [ } ] -{ #category : #accessing } -DiyaExampleApp >> main [ - +{ #category : #initialization } +DiyaExampleApp >> initLoader [ + loader := DiyaDefaultAppLoader new. ] { #category : #accessing } -DiyaExampleApp >> setup [ - |node node1 img ell label icon button texture loading| - texture := DiyaImageTex new. - "DiyaRendererContext uniqueInstance assets - addAsset: - ((Form fromDisplay: ( Rectangle origin: 0@0 corner: 300@300 )) asDiyaTexture: 'display')." - self defineStyleSheet. - label := root addNode: (DiyaLabel new) at: 10@40. - label extent: 250@24. - label styleName:#text_icon_1. - label icon: 16rF254. +DiyaExampleApp >> onloaded: aBlock [ + loader job: [ self defineStyleSheet ] name: 'Initializing themes...'. + loader job: [ + self defineNodes. + self node forceReload + ] name: 'Initializing UI elements...'. - node1 := root addNode: (DiyaRectangle size:100@150 shader: DiyaExampleShader uniqueInstance) at: 300 @ 40. - node1 rotation: 45. - node1 scale: 2.0@2.0. - node1 on: #(mousebuttondown fingerdown) do:[:e| - label txt: 'RECT ', (node1 local: e mapped worldPosition) asIntegerPoint asString]. - - img := root addNode: (DiyaImageView from:'mrsang.png') at: 10 @ 400. - img styleName: #image_view. - img extent:200@200. - root on: #(mousebuttondown fingerdown) do:[:e| - "change texture" - |p| - p := e mapped worldPosition. - label txt: 'Mouse ', p asIntegerPoint asString. - DiyaRenderer assets - addAsset:(texture fromDisplay: (Rectangle origin: ((p x - 100) @ (p y - 100)) extent: 200@200 ) as: 'capture'). - img textureNamed: 'capture'. - - ]. - - node := root addNode: (DiyaRectangle new) at: 10@80. - node styleName: #rect_view. - node extent: 240@320. - - node := root addNode: (DiyaText data: String loremIpsum) at: 10@80. - node extent: 240@320. - node wordWrap: true. - node styleName: #text_view. - - node := root addNode: (DiyaLine from: 10@10 to: 200@200). - node styleName: #line_view. - - ell := root addNode: (DiyaEllipse rx:100 ry: 70) at: 120@300. - ell scale: 1.2 @ 1.2. - ell styleName: #ell_view. - "ell rotation: 30." - ell textureNamed:'mrsang.png'. - ell addNode: (DiyaTimerNode timeout: 1000 / 6 do:[:n | - n parent rotation: n parent rotation + 10. - ] ). - ell on: #(mousebuttondown fingerdown) do:[:e| - label txt: 'Ellipse clicked', (ell local:e mapped worldPosition) asIntegerPoint asString]. - - node := root addNode: (DiyaConvexPolygon points:{0@40. 150@190. 200@20. 100@0}) at: 250@60. - node textureNamed: 'mrsang.png'. - node styleName: #poly_view. - - icon := root addNode: (DiyaFontIcon data: #(16rF101 16rF155 16rF185 16rF21B 16rF298 16rF254)) at: 240@500. - icon styleName: #text_icon_2. - - button := root addNode: (DiyaButton text: 'Click me !') at: 240@460. - icon := DiyaFontIcon data: 16rF130. - "icon := DiyaImageIcon from: 'mrsang.png'." - icon addNode:(DiyaTimerNode timeout: 1000 / 12 do:[:n | - n parent rotation: n parent rotation + 10 pivot: n parent extent / 2. - ] ). - button extent: 200@40. - button icon: icon "'mrsang.png'". - "button rotation: Float pi / 2.0." - button styleName: #button_view. - - loading := root addNode: (DiyaLoadingBar new) at: 240@550. - loading extent: 200 @ 20. - - loading addNode: (DiyaTimerNode timeout: 2000 do:[:n | - |p| - p := (n parent percent + 10). - p > 100 ifTrue:[ p := 0]. - n parent percent: p. - ] ). - - - loading := root addNode: (DiyaLoadingBar new) at: 240@580. - loading extent: 200 @ 20. - - loading addNode: (DiyaTimerNode timeout: 1000 do:[:n | - |p| - p := (n parent percent + 10). - p > 100 ifTrue:[ p := 0]. - n parent percent: p. - ] ). - ^ root + loader onloaded: aBlock ] diff --git a/Diya/DiyaLoader.class.st b/Diya/DiyaLoader.class.st new file mode 100644 index 0000000..30785ad --- /dev/null +++ b/Diya/DiyaLoader.class.st @@ -0,0 +1,54 @@ +Class { + #name : #DiyaLoader, + #superclass : #DiyaBaseObject, + #instVars : [ + 'node', + 'jobs' + ], + #category : #'Diya-Applications' +} + +{ #category : #scheduling } +DiyaLoader >> executeJobs: callback [ + jobs withIndexDo: [ :job :i| + self updateProgress: job key percent: ((i - 1) * 100 / (jobs size)) asInteger. + job value value. + ]. + jobs := OrderedCollection new. + self updateProgress: 'Finishing...' percent: 100. + 500 milliSeconds wait. + callback value. +] + +{ #category : #initialization } +DiyaLoader >> init [ + self subclassResponsibility +] + +{ #category : #initialization } +DiyaLoader >> initialize [ + super initialize. + node := DiyaCompositeNode new. + jobs := OrderedCollection new. + self init. +] + +{ #category : #scheduling } +DiyaLoader >> job: aBlock name: aName [ + jobs add: (aName -> aBlock) +] + +{ #category : #accessing } +DiyaLoader >> node [ + ^ node +] + +{ #category : #scheduling } +DiyaLoader >> onloaded: aBlock [ + [ self executeJobs: aBlock ] fork"At: Processor userBackgroundPriority". +] + +{ #category : #scheduling } +DiyaLoader >> updateProgress: name percent: p [ + self subclassResponsibility +] diff --git a/Diya/DiyaNode.class.st b/Diya/DiyaNode.class.st index 9f9b9dd..d4f973a 100644 --- a/Diya/DiyaNode.class.st +++ b/Diya/DiyaNode.class.st @@ -14,6 +14,7 @@ Class { 'root', 'styleName', 'style', + 'inlineStyle', 'id', 'visibility', 'pivot' @@ -31,9 +32,11 @@ DiyaNode class >> with: shader [ ^self new shader: shader; yourself ] -{ #category : #accessing } +{ #category : #styling } DiyaNode >> ? styleAttr [ | value| + value := inlineStyle at: styleAttr ifAbsent:[nil]. + value ifNotNil: [ ^value ]. styleName ifNotNil: [ style ifNil: [ style := DiyaUIThemesManager uniqueInstance currentTheme ? (self styleName). @@ -90,7 +93,6 @@ DiyaNode >> extent [ { #category : #processing } DiyaNode >> forceReload [ self process. - self setClean. children ifNotNil: [ children do:[:c| c forceReload @@ -113,11 +115,17 @@ DiyaNode >> initialize [ styleName := nil. style := nil. root := nil. + inlineStyle := Dictionary new. visibility := true. pivot := 0@0. id := self className,'#',(Random new nextInt: 1e6) asString. ] +{ #category : #styling } +DiyaNode >> inlineStyle: name value: value [ + inlineStyle at: name put: value +] + { #category : #testing } DiyaNode >> inner: aPoint [ ^ self subclassResponsibility diff --git a/Diya/DiyaRendererContext.class.st b/Diya/DiyaRendererContext.class.st index 3f4531e..a242a5d 100644 --- a/Diya/DiyaRendererContext.class.st +++ b/Diya/DiyaRendererContext.class.st @@ -135,7 +135,7 @@ DiyaRendererContext >> root [ { #category : #rendering } DiyaRendererContext >> submitData: vbuffer [ - vbo data: GL_ARRAY_BUFFER data: vbuffer usage: GL_DYNAMIC_DRAW. + vbo data: GL_ARRAY_BUFFER data: vbuffer usage: GL_STATIC_DRAW. ] { #category : #'transformation matrices' } diff --git a/Diya/DiyaText.class.st b/Diya/DiyaText.class.st index f8461ab..09bd8e6 100644 --- a/Diya/DiyaText.class.st +++ b/Diya/DiyaText.class.st @@ -206,9 +206,6 @@ DiyaText >> process [ data ifNil:[^true]. data ifEmpty:[^true]. texture ifNil: [ self initTexture ]. - texheight = texture height ifFalse: [ - texheight := texture height. - ]. vbuffer ifNotNil: [vbuffer free]. vbuffer := FFIExternalArray externalNewType: GLfloat size: data size * 16. vbuffer autoRelease. @@ -230,6 +227,14 @@ DiyaText >> splitLines [ ] whileTrue. ] +{ #category : #stepping } +DiyaText >> step [ + texture ifNil: [ ^self ]. + texheight = texture height ifTrue: [ ^self]. + texheight := texture height. + self setDirty +] + { #category : #accessing } DiyaText >> styleName: aName [ super styleName: aName.