1
0
mirror of https://github.com/lxsang/Diya-API.git synced 2024-12-26 03:18:22 +01:00

API improvements:

- fix: TF update bug on scale
- fix: Use local coordiate for Polygon points
- Add timer node for basic animation
- Dirty processing nodes are monitored by rootnode
- refactory code
This commit is contained in:
Dany LE 2022-08-12 22:19:54 +02:00
parent 2ee103191c
commit 2e4c73f8cf
14 changed files with 267 additions and 67 deletions

View File

@ -77,11 +77,22 @@ Diya2DNode >> recFromBuffer [
Diya2DNode >> updateTF [
tf := MatrixTransform2x3 identity.
"translation"
tf setOffset: translation.
tf setOffset: translation + pivot.
"rotation"
rotation = 0 ifFalse:[tf setAngle: rotation ].
"scale"
tf setScale: scale.
"translate back to pivot"
pivot isZero ifFalse:[
tf := tf composedWithLocal:
(MatrixTransform2x3 identity
setOffset: pivot negated;
yourself)
].
scale isZero ifFalse: [
tf := tf composedWithLocal:
(MatrixTransform2x3 identity
setScale: scale;
yourself)
].
self parent ifNil: [ ^self ].
self parent isRoot ifFalse: [tf := self parent tf composedWithLocal: tf ].
children ifNotNil: [children do:[:c| c updateTF ]].

View File

@ -75,7 +75,6 @@ Diya2DPrimShape >> extent [
Diya2DPrimShape >> initialize [
super initialize.
texture := nil.
children := nil.
type := GL_TRIANGLES.
bbox := Rectangle origin: 0@0 corner: 0@0.
]

View File

@ -47,9 +47,11 @@ DiyaApplicationLauncher >> launch: app [
root empty.
].
currapp := app uniqueInstance.
self appNode addNode: currapp root.
currapp setup.
currapp root forceReload.
Transcript show: 'APPLICATION INIT'; cr.
self context assets: currapp am.
currapp setup
self appNode addNode: currapp root.
]
{ #category : #initialization }
@ -64,7 +66,7 @@ DiyaApplicationLauncher >> main [
].
currapp ifNotNil: [currapp main.].
"root render."
[ root stepDown ] fork.
root stepDown.
self process.
root render.
]
@ -73,11 +75,12 @@ DiyaApplicationLauncher >> main [
DiyaApplicationLauncher >> process [
|Q node maxProcessingTime|
maxProcessingTime := 1000 / DiyaBoot maxFPS - 100.
Q := DiyaRendererContext uniqueInstance processQueue.
Q := root processingQueue select:[:e| e visibility].
Q ifEmpty:[^ self].
[
node := Q removeFirst.
node process.
root cleanDirtyNode: node.
Q isNotEmpty and: DiyaClock uniqueInstance lapDelta asMilliSeconds < maxProcessingTime
] whileTrue
@ -102,7 +105,7 @@ DiyaApplicationLauncher >> setup [
#bgColor -> Color orange.
#border -> 3
}.
root addNode: (Diya2DNode new) at: 0@0.
root addNode: (DiyaCompositeNode new) at: 0@0.
txtFPS := root addNode:(DiyaText data: '') at: ( self context resolution x - 80)@(self context resolution y - 40).
txtFPS extent: 80@40.
txtFPS styleName: #fps_text.

View File

@ -7,6 +7,7 @@ Class {
{ #category : #initialization }
DiyaBaseApplication >> initialize [
super initialize.
root := Diya2DNode new.
root := DiyaCompositeNode new.
root styleName: #global.
am := AssetManager new.
]

View File

@ -0,0 +1,22 @@
Class {
#name : #DiyaCompositeNode,
#superclass : #Diya2DNode,
#category : #'Diya-Graphics'
}
{ #category : #accessing }
DiyaCompositeNode >> process [
]
{ #category : #accessing }
DiyaCompositeNode >> setClean [
]
{ #category : #accessing }
DiyaCompositeNode >> setDirty [
]

View File

@ -92,6 +92,6 @@ DiyaEllipse >> setUpShader [
self shader
setUniform: #u_border value: (self ? #border);
setUniform: #u_border_color value: ( self ? #borderColor) asGL4FArray;
setUniform: #u_rx value: rx;
setUniform: #u_ry value: ry.
setUniform: #u_rx value: (rx * (scale x)) ;
setUniform: #u_ry value: (ry * (scale y)) .
]

View File

@ -89,7 +89,7 @@ DiyaExampleApp >> setup [
node1 rotation: 45.
node1 scale: 2.0@2.0.
node1 on: #(mousebuttondown fingerdown) do:[:e|
label txt: 'Mouse ', (node1 local: e mapped worldPosition) asIntegerPoint asString].
label txt: 'RECT ', (node1 local: e mapped worldPosition) asIntegerPoint asString].
img := root addNode: (DiyaImageView from:'mrsang.png') at: 10 @ 400.
img styleName: #image_view.
@ -117,15 +117,17 @@ DiyaExampleApp >> setup [
node := root addNode: (DiyaLine from: 10@10 to: 200@200).
node styleName: #line_view.
ell := root addNode: (DiyaEllipse rx:100 ry: 70) at: 100@300.
ell rotation: 30.
ell := root addNode: (DiyaEllipse rx:100 ry: 70) at: 120@300.
ell scale: 1.2 @ 1.2.
ell styleName: #ell_view.
"node rotation: Float pi / 2.0."
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:{250@100. 400@250. 450@80. 350@60}).
node := root addNode: (DiyaConvexPolygon points:{0@40. 150@190. 200@20. 100@0}) at: 250@60.
node textureNamed: 'mrsang.png'.
node styleName: #poly_view.
@ -133,8 +135,13 @@ DiyaExampleApp >> setup [
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:16rF185"'mrsang.png'".
button icon: icon "'mrsang.png'".
"button rotation: Float pi / 2.0."
button styleName: #button_view.
Transcript show: 'Application setup';cr.

View File

@ -32,7 +32,7 @@ DiyaLabel >> icon: anObject [
anObject isString ifTrue: [
icon := self addNode: (DiyaImageIcon from: anObject).
].
icon ifNil: [ ^ DiyaCoreAPIError signal: 'Invalid icon identification'].
icon ifNil: [ icon := self addNode: anObject ].
self setDirty
]

View File

@ -0,0 +1,40 @@
Class {
#name : #DiyaMetaNode,
#superclass : #DiyaNode,
#category : #'Diya-Graphics'
}
{ #category : #accessing }
DiyaMetaNode >> addNode: node at: pos [
self shouldNotBeCalled
]
{ #category : #accessing }
DiyaMetaNode >> boundingBox [
^ 0@0
]
{ #category : #rendering }
DiyaMetaNode >> draw [
]
{ #category : #accessing }
DiyaMetaNode >> extent [
^ 0@0
]
{ #category : #testing }
DiyaMetaNode >> inner: aPoint [
^ false
]
{ #category : #processing }
DiyaMetaNode >> process [
]
{ #category : #processing }
DiyaMetaNode >> updateTF [
]

View File

@ -14,7 +14,9 @@ Class {
'root',
'styleName',
'style',
'id'
'id',
'visibility',
'pivot'
],
#pools : [
'OpenGLConstants',
@ -53,25 +55,13 @@ DiyaNode >> addNode: node [
DiyaNode >> addNode: node at: pos [
children ifNil: [ ^self ].
node parent: self.
node position: pos.
children add: node.
node position: pos.
node root: self root.
node setDirtyAll.
^ node
]
{ #category : #accessing }
DiyaNode >> allChildren [
|nodes|
nodes := OrderedCollection new.
children ifNil: [ ^ nodes ].
children do:[:c|
nodes add: c.
c allChildren do:[:e| nodes add:e].
].
^nodes
]
{ #category : #accessing }
DiyaNode >> boundingBox [
^ self subclassResponsibility
@ -82,7 +72,7 @@ DiyaNode >> children [
^children
]
{ #category : #accessing }
{ #category : #rendering }
DiyaNode >> draw [
self subclassResponsibility
]
@ -97,6 +87,15 @@ DiyaNode >> extent [
^ self subclassResponsibility
]
{ #category : #processing }
DiyaNode >> forceReload [
self process.
children ifNotNil: [
children do:[:c|
c forceReload
]]
]
{ #category : #accessing }
DiyaNode >> id [
^ id
@ -113,10 +112,12 @@ DiyaNode >> initialize [
styleName := nil.
style := nil.
root := nil.
visibility := true.
pivot := 0@0.
id := self className,'#',(Random new nextInt: 1e6) asString.
]
{ #category : #accessing }
{ #category : #testing }
DiyaNode >> inner: aPoint [
^ self subclassResponsibility
]
@ -143,6 +144,11 @@ DiyaNode >> parent: anObject [
parent := anObject
]
{ #category : #accessing }
DiyaNode >> pivot [
^ pivot
]
{ #category : #accessing }
DiyaNode >> position [
^ translation
@ -154,7 +160,7 @@ DiyaNode >> position: anObject [
self updateTF.
]
{ #category : #accessing }
{ #category : #processing }
DiyaNode >> process [
^self subclassResponsibility
]
@ -163,13 +169,26 @@ DiyaNode >> process [
DiyaNode >> register: aBlock to: eventName [
|evtCode|
evtCode := SDL2Constants bindingOf: ('SDL_', eventName asUppercase).
evtCode ifNil: [ ^DiyaCoreAPIError signal: 'Unknow event ', eventName ].
evtCode ifNil: [ evtCode := eventName ].
ehandlers at: evtCode value put: aBlock.
]
{ #category : #accessing }
{ #category : #removing }
DiyaNode >> remove [
self setClean.
root := nil.
parent ifNotNil: [ parent removeChild: self ]
]
{ #category : #removing }
DiyaNode >> removeChild: c [
children ifNotNil: [ children remove: c ifAbsent:[ ]]
]
{ #category : #rendering }
DiyaNode >> render [
visibility ifFalse:[^self].
shader ifNotNil: [self setUpShader].
self draw.
children ifNil: [ ^self ].
@ -201,6 +220,13 @@ DiyaNode >> rotation: anObject [
self updateTF.
]
{ #category : #accessing }
DiyaNode >> rotation: anObject pivot: p [
rotation := anObject.
pivot := p.
self updateTF.
]
{ #category : #accessing }
DiyaNode >> scale [
^ scale
@ -212,21 +238,26 @@ DiyaNode >> scale: anObject [
self updateTF.
]
{ #category : #initialization }
{ #category : #'changing state' }
DiyaNode >> setClean [
|Q|
Q := DiyaRendererContext uniqueInstance processQueue.
Q remove: self ifAbsent: [ ]
root ifNil: [ ^self ].
root cleanDirtyNode: self.
]
{ #category : #initialization }
{ #category : #'changing state' }
DiyaNode >> setDirty [
|Q|
Q := DiyaRendererContext uniqueInstance processQueue.
(Q includes: self ) ifFalse:[ Q add: self].
root ifNil: [ ^self ].
self root enqueueDirtyNode: self.
]
{ #category : #accessing }
{ #category : #'changing state' }
DiyaNode >> setDirtyAll [
self setDirty.
children ifNotNil: [
children do:[:c| c setDirtyAll] ]
]
{ #category : #rendering }
DiyaNode >> setUpShader [
|mem|
mem := self tf asGLBuffer.
@ -264,7 +295,7 @@ DiyaNode >> step [
{ #category : #stepping }
DiyaNode >> stepDown [
self step
self step.
children ifNotNil: [ children do:[:c | c stepDown ] ]
]
@ -303,7 +334,17 @@ DiyaNode >> trigger: evt [
].
]
{ #category : #accessing }
{ #category : #processing }
DiyaNode >> updateTF [
self subclassResponsibility
]
{ #category : #accessing }
DiyaNode >> visibility [
^ visibility
]
{ #category : #accessing }
DiyaNode >> visibility: anObject [
visibility := anObject
]

View File

@ -42,9 +42,6 @@ DiyaPolygon >> points: anObject [
{ #category : #accessing }
DiyaPolygon >> process [
bbox := self recFromPoints.
translation = bbox origin ifFalse:[ self position: bbox origin].
points := points collect:[:e | e - bbox origin].
bbox := self recFromPoints.
self calculateVertices.
^true

View File

@ -9,8 +9,7 @@ Class {
'texture0',
'projection',
'assets',
'window',
'rqueue'
'window'
],
#pools : [
'OpenGLConstants',
@ -67,7 +66,6 @@ DiyaRendererContext >> initialize [
vbo bind: GL_ARRAY_BUFFER.
projection := Array2D identity: 4.
assets := AssetManager new.
rqueue := OrderedCollection new.
]
{ #category : #accessing }
@ -80,11 +78,6 @@ DiyaRendererContext >> mouse: anObject [
mouse := anObject
]
{ #category : #accessing }
DiyaRendererContext >> processQueue [
^ rqueue
]
{ #category : #accessing }
DiyaRendererContext >> projection [
^ projection

View File

@ -12,16 +12,16 @@ DiyaRootNode >> Q [
^ Q
]
{ #category : #accessing }
DiyaRootNode >> Q: v [
Q := v
]
{ #category : #accessing }
DiyaRootNode >> boundingBox [
^ Rectangle origin: 0@0 corner: context resolution
]
{ #category : #'add/remove' }
DiyaRootNode >> cleanDirtyNode: aNode [
Q remove: aNode ifAbsent:[]
]
{ #category : #accessing }
DiyaRootNode >> draw [
|c|
@ -31,6 +31,11 @@ DiyaRootNode >> draw [
context vbo bind: GL_ARRAY_BUFFER.
]
{ #category : #'add/remove' }
DiyaRootNode >> enqueueDirtyNode: aNode [
(Q includes: aNode ) ifFalse:[ Q add: aNode].
]
{ #category : #accessing }
DiyaRootNode >> extent [
^ context resolution
@ -58,7 +63,7 @@ DiyaRootNode >> isRoot [
{ #category : #initialization }
DiyaRootNode >> process [
^true
]
{ #category : #accessing }
@ -66,6 +71,19 @@ DiyaRootNode >> processingQueue [
^ Q
]
{ #category : #initialization }
DiyaRootNode >> setClean [
]
{ #category : #initialization }
DiyaRootNode >> setDirty [
]
{ #category : #accessing }
DiyaRootNode >> updateTF [
"donothing"

View File

@ -0,0 +1,68 @@
Class {
#name : #DiyaTimerNode,
#superclass : #DiyaMetaNode,
#instVars : [
'timeout',
'elapsedTime',
'handlers'
],
#category : #'Diya-Graphics'
}
{ #category : #accessing }
DiyaTimerNode class >> timeout: ms [
^ self new timeout: ms; yourself
]
{ #category : #accessing }
DiyaTimerNode class >> timeout: ms do: aBlock [
^ (self timeout: ms) onTimeout: aBlock;yourself
]
{ #category : #accessing }
DiyaTimerNode class >> timeout: ms doOnce: aBlock [
^ (self timeout: ms) onceTimeout: aBlock;yourself
]
{ #category : #accessing }
DiyaTimerNode >> delta [
^ DiyaClock uniqueInstance delta asMilliSeconds
]
{ #category : #accessing }
DiyaTimerNode >> initialize [
super initialize.
elapsedTime := 0.
handlers := OrderedCollection new.
]
{ #category : #'as yet unclassified' }
DiyaTimerNode >> onTimeout: aBlock [
handlers add: aBlock
]
{ #category : #'as yet unclassified' }
DiyaTimerNode >> onceTimeout: aBlock [
|newBlock|
handlers := OrderedCollection new.
newBlock := [ :node | aBlock value: node. self remove ].
handlers add: newBlock
]
{ #category : #stepping }
DiyaTimerNode >> step [
elapsedTime := elapsedTime + self delta.
elapsedTime >= timeout ifFalse:[^ self].
handlers do:[:e| e value: self ].
elapsedTime := 0
]
{ #category : #accessing }
DiyaTimerNode >> timeout [
^ timeout
]
{ #category : #accessing }
DiyaTimerNode >> timeout: anObject [
timeout := anObject
]