1
0
mirror of https://github.com/lxsang/Diya-API.git synced 2025-07-16 22:09:47 +02:00

36 Commits

Author SHA1 Message Date
f10ad2449c Update Jenkinsfile
All checks were successful
gitea-sync/Diya-API/pipeline/head This commit looks good
2022-09-26 10:57:19 +02:00
0faefcae12 Update Jenkinsfile
Some checks reported errors
gitea-sync/Diya-API/pipeline/head Something is wrong with the build of this commit
2022-09-26 10:55:46 +02:00
85968f7b6a Update Jenkinsfile 2022-09-26 10:55:04 +02:00
b393432256 Update Jenkinsfile
Some checks reported errors
gitea-sync/Diya-API/pipeline/head Something is wrong with the build of this commit
2022-09-26 10:53:41 +02:00
8639bc4d65 Update Jenkinsfile
Some checks are pending
gitea-sync/Diya-API/pipeline/head Build queued...
2022-09-26 10:53:34 +02:00
79e42786e8 Update Jenkinsfile
Some checks failed
gitea-sync/Diya-API/pipeline/head There was a failure building this commit
2022-09-26 10:52:20 +02:00
cf89a8ca59 Update Jenkinsfile
Some checks failed
gitea-sync/Diya-API/pipeline/head There was a failure building this commit
2022-09-26 10:44:52 +02:00
f61e17de9c rendering improvement
Some checks reported errors
gitea-sync/Diya-API/pipeline/head Something is wrong with the build of this commit
2022-08-16 00:59:35 +02:00
3c00e1d181 refactory code, support inline style, improve text rendering 2022-08-15 12:28:09 +02:00
0b7396242a Refactor code on System clock 2022-08-14 22:49:36 +02:00
681d8951b7 remove unused selectors 2022-08-14 22:38:06 +02:00
0e78e6769d Meta node should not visible 2022-08-14 22:22:39 +02:00
8978c06efa Initialize global vars 2022-08-14 18:33:19 +02:00
74ce2b0f37 Supporting read system settings from file 2022-08-14 18:13:23 +02:00
2d09a8501a Refactory code 2022-08-14 16:52:22 +02:00
142f14e936 Rendering context now use multiple texture units to boost performance (on RPI zero, the performance gain is more than 10 FPS ) 2022-08-14 15:42:59 +02:00
677145f1a1 Add missing code of the previous commit 2022-08-14 01:39:09 +02:00
26368c37ab Rendering improvement: render a limited number of nodes (based on FPS setting) on the back buffer each iterration.
The back buffer is only swapped when all nodes are rendered
2022-08-14 01:38:22 +02:00
c7af75550f code refactory on rendering context 2022-08-13 23:48:23 +02:00
c1f2de2896 refactory code 2022-08-13 15:55:51 +02:00
766ae23f8e fix: incorrect line rendering 2022-08-13 01:47:15 +02:00
f3ef0c1aa0 fix: tf global to local problem on 2D node, add LoadingBar widget, and refactor code 2022-08-13 01:37:42 +02:00
2e4c73f8cf 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
2022-08-12 22:19:54 +02:00
2ee103191c OPENGL Rendering Performance improvement 2022-08-12 16:37:53 +02:00
a3d00d52ef Allow to fallback to VM plugins for image handling if SDL_image lib doesnt exist 2022-08-12 12:02:49 +02:00
133ddb0380 Fix: incorrect index in buffer converting 2022-08-10 23:05:25 +02:00
598e252b9e fix: add missing extension 2022-08-10 23:00:30 +02:00
664e2169f3 Refactor code + use primitive for 2D matrix transformation 2022-08-10 22:53:14 +02:00
9442050825 API improvement
- Refactor code
- Texture performance improvement
2022-08-10 19:55:49 +02:00
6f5c6b8551 allow get texture from screen, VM bug on device 2022-08-09 03:14:23 +02:00
141bf2e226 use SDL2_image for texture loading 2022-08-09 00:22:18 +02:00
676113a697 Add global display object that refers to current SDL display 2022-08-08 16:35:04 +02:00
4a95c7d6df remove dependecy on OSSDL2Driver 2022-08-08 13:11:25 +02:00
7a7665430d Remove dependencies on OSSDLDriver 2022-08-08 13:03:46 +02:00
8b6a7927f4 Correct openGL transparent color display problem, stylesheet now allows style inheritance 2022-08-08 00:12:54 +02:00
007d99804f Cache current stylesheet object in each node to gain FPS 2022-08-07 21:08:29 +02:00
60 changed files with 1652 additions and 568 deletions

View File

@ -1,5 +1,15 @@
Extension { #name : #Array }
{ #category : #'*Diya' }
Array >> asDiyaStyle [
|style|
style := DiyaStyle new.
self do:[:v |
style at: v key put: v value
].
^style
]
{ #category : #'*Diya' }
Array >> asPoint [
^ (self at: 1 ifAbsent:[0]) @ (self at: 2 ifAbsent:[0])

View File

@ -1,41 +0,0 @@
Extension { #name : #Array2D }
{ #category : #'*Diya' }
Array2D >> asGLBuffer [
|buffer i|
i := 1.
buffer := FFIExternalArray externalNewType: #float size: self size.
self asArray do:[:e|
buffer at:i put:e.
i := i+1
].
buffer autoRelease.
^buffer
]
{ #category : #'*Diya' }
Array2D class >> rotationMatrix2D: rotation [
^Array2D rows: 3 columns: 3 contents:{
rotation cos. (rotation sin) negated. 0.0.
rotation sin. rotation cos. 0.0.
0.0. 0.0. 1.0
}
]
{ #category : #'*Diya' }
Array2D class >> scaleMatrix2D: scale [
^Array2D rows: 3 columns: 3 contents:{
scale x. 0.0. 0.0.
0.0. scale y. 0.0.
0.0. 0.0. 1.0
}
]
{ #category : #'*Diya' }
Array2D class >> translateMatrix2D: translation [
^Array2D rows: 3 columns: 3 contents: {
1.0. 0.0. translation x.
0.0. 1.0. translation y.
0.0. 0.0. 1.0
}
]

View File

@ -8,18 +8,24 @@ Class {
#category : #'Diya-Core'
}
{ #category : #'instance creation' }
AssetManager class >> defaultAssetLocation [
^Smalltalk imageDirectory / 'assets'
]
{ #category : #'instance creation' }
AssetManager class >> fromLocation: loc [
^self new from: loc; yourself
]
{ #category : #'as yet unclassified' }
{ #category : #adding }
AssetManager >> addAsset: value [
assets at: value name put: value.
^ value
]
{ #category : #adding }
AssetManager >> addAssetName: name value: value [
assets at: name put: value.
^ value
]
{ #category : #'instance creation' }
AssetManager >> from: location [
base := location
]
@ -28,15 +34,21 @@ AssetManager >> from: location [
AssetManager >> initialize [
super initialize.
assets := Dictionary new.
base := self class defaultAssetLocation
base := DiyaSystemSettings assetPath
]
{ #category : #'as yet unclassified' }
AssetManager >> name: fileName of: type [
^assets at: fileName ifAbsentPut: [(type fromFile: (base / fileName))].
{ #category : #accessing }
AssetManager >> name: name [
^assets at: name.
]
{ #category : #'as yet unclassified' }
{ #category : #accessing }
AssetManager >> name: name of: type [
^assets at: name ifAbsentPut: [
(type fromFile: (base / name))].
]
{ #category : #accessing }
AssetManager >> texture: name [
^self name: name of: DiyaImageTex
]

View File

@ -0,0 +1,6 @@
Extension { #name : #DiskStore }
{ #category : #'*Diya' }
DiskStore class >> inform: string [
Transcript show: string; cr.
]

View File

@ -40,7 +40,7 @@ Diya2DNode >> initialize [
translation := 0@0.
scale := 1@1.
rotation := 0.
tf := Array2D identity: 3.
tf := MatrixTransform2x3 identity .
shader := Diya2DShader uniqueInstance.
vbuffer := nil.
]
@ -52,8 +52,7 @@ Diya2DNode >> inner: aPoint [
{ #category : #accessing }
Diya2DNode >> local: aPoint [
^((aPoint - (0@0 applyTf: self tf) )/ scale)
rotateBy: rotation about: 0@0.
^ self tf globalPointToLocal: aPoint
]
@ -75,18 +74,26 @@ Diya2DNode >> recFromBuffer [
{ #category : #accessing }
Diya2DNode >> updateTF [
tf := Array2D identity:3.
tf := MatrixTransform2x3 identity.
"translation"
translation = (0@0) ifFalse:[
tf := tf +* (Array2D translateMatrix2D: translation)].
tf setOffset: translation + pivot.
"rotation"
rotation = 0 ifFalse:[
tf := tf +* (Array2D rotationMatrix2D: rotation )].
"scale"
scale = (1@1) ifFalse:[
tf := tf +* (Array2D scaleMatrix2D: scale)].
rotation = 0 ifFalse:[tf setAngle: rotation ].
"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 +* tf ].
self parent isRoot ifFalse: [tf := self parent tf composedWithLocal: tf ].
children ifNotNil: [children do:[:c| c updateTF ]].
]

View File

@ -16,26 +16,29 @@ Diya2DPrimShape >> borderWidth [
{ #category : #accessing }
Diya2DPrimShape >> boundingBox [
^ bbox applyTf: self tf.
^ self tf localBoundsToGlobal: bbox.
]
{ #category : #initialization }
Diya2DPrimShape >> draw [
vbuffer ifNil: [ ^self ].
OpenGL
enable: GL_CULL_FACE;
enable: GL_BLEND;
blendFnWithSfactor: GL_SRC_ALPHA dfactor: GL_ONE_MINUS_SRC_ALPHA.
"configure vao vbo for texture QUAD"
self texture ifNotNil: [
self texture setup.
context texture0 setImage2D: self texture.
context texture0 active.
context useTexture: self texture.
].
context vao enableAttribute: 0.
OpenGLVertexArray vertexAttributePointerIndex: 0 size:4 type: GL_FLOAT normalized: GL_FALSE stride: 16 pointer: nil .
context vbo data: GL_ARRAY_BUFFER data: vbuffer usage: GL_STATIC_DRAW.
context submitData: vbuffer.
OpenGL drawArrays: type first:0 count:((vbuffer size )>> 2 ).
"reset value"
self texture ifNotNil: [self texture drop.].
self borderWidth > 0 ifTrue: [ self drawBorder ].
context vao disableAttribute: 0.
OpenGL
disable: GL_CULL_FACE;
disable: GL_BLEND.
]
{ #category : #initialization }
@ -68,7 +71,6 @@ Diya2DPrimShape >> extent [
Diya2DPrimShape >> initialize [
super initialize.
texture := nil.
children := nil.
type := GL_TRIANGLES.
bbox := Rectangle origin: 0@0 corner: 0@0.
]
@ -84,9 +86,16 @@ Diya2DPrimShape >> setUpShader [
super setUpShader.
self shader
setUniform: #u_color value: (self ? #color) asGL4FArray;
setUniform: #u_bg_color value: (self ? #bgColor) asGL4FArray;
setUniform: #u_texture_type value:
(self texture ifNil: [ 0 ] ifNotNil:[self texture format]).
setUniform: #u_bg_color value: (self ? #bgColor) asGL4FArray.
self texture ifNotNil: [
self shader
setUniform: #u_texture value: self texture unit;
setUniform: #u_texture_type value: self texture format.
]
ifNil:
[
self shader setUniform: #u_texture_type value: 0.
].
]
{ #category : #accessing }

View File

@ -20,7 +20,13 @@ uniform vec4 u_bg_color;
uniform sampler2D u_texture;
varying vec2 texcoord;
void main(void) {
vec4 texcolor = vec4(0,0,0,0);
if(u_texture_type == 1)
{
// draw border
gl_FragColor = u_color;
return;
}
vec4 texcolor = u_bg_color;
// alpha
if(u_texture_type == 0x1906) {
texcolor = vec4(1, 1, 1, texture2D(u_texture, texcoord).a);
@ -29,10 +35,6 @@ void main(void) {
else if (u_texture_type == 0x1908){
texcolor = texture2D(u_texture, texcoord);
}
else if(u_texture_type == 1)
{
texcolor = vec4(1,1,1,1);
}
vec4 pxcolor = texcolor * u_color;
if(pxcolor.a > 0.0)
{

View File

@ -4,7 +4,6 @@ Class {
#instVars : [
'currapp',
'txtFPS',
'event',
'running'
],
#category : #'Diya-Applications'
@ -12,20 +11,19 @@ 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| Transcript show: 'keydown...';cr. running := false.].
root on: #quit do: [:e| running := false].
root on: #(fingerdown fingermotion mousemotion) do:[:e|
target on: #keydown do:[:e| self stdlog: 'keydown...'. running := false.].
target on: #quit do: [:e| running := false].
target on: #(fingerdown fingermotion mousemotion) do:[:e|
pointer position: e mapped worldPosition.
"Transcript show: e mapped worldPosition asString;cr."
DiyaRendererContext uniqueInstance mouse: (e mapped x) @ (e mapped y).
DiyaRenderer mouse: (e mapped x) @ (e mapped y).
].
]
@ -34,50 +32,8 @@ DiyaApplicationLauncher >> defaultApplication [
^DiyaExampleApp
]
{ #category : #'as yet unclassified' }
DiyaApplicationLauncher >> delta: delta [
|fps|
delta = 0 ifTrue:[^self].
fps := ((1000/delta) asInteger).
txtFPS data: ('FPS:', fps asString).
]
{ #category : #initialization }
DiyaApplicationLauncher >> initialize [
super initialize.
root := DiyaRootNode new.
currapp := nil.
]
{ #category : #initialization }
DiyaApplicationLauncher >> launch: app [
currapp ifNotNil: [
currapp quit.
root empty.
].
currapp := app uniqueInstance.
self appNode addNode: currapp root.
self context assets: currapp am.
currapp setup.
]
{ #category : #initialization }
DiyaApplicationLauncher >> main [
[(SDL2 pollEvent: event) > 0] whileTrue: [
root trigger: (DiyaEvent from: event mapped).
].
currapp ifNotNil: [currapp main.].
root render.
]
{ #category : #accessing }
DiyaApplicationLauncher >> running [
^ running
]
{ #category : #initialization }
DiyaApplicationLauncher >> setup [
event := SDL_Event new.
DiyaApplicationLauncher >> defineLayout [
DiyaUIThemesManager uniqueInstance currentTheme
define: #fps_text styles: {
#color -> Color red.
@ -89,11 +45,60 @@ DiyaApplicationLauncher >> setup [
#bgColor -> Color orange.
#border -> 3
}.
root addNode: (Diya2DNode 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.
self loadNode.
]
{ #category : #initialization }
DiyaApplicationLauncher >> initialize [
super initialize.
node := DiyaCompositeNode new.
currapp := nil.
]
{ #category : #initialization }
DiyaApplicationLauncher >> launch: app [
currapp ifNotNil: [
currapp quit.
].
currapp := app uniqueInstance.
self context assets: currapp am.
currapp target: self appNode.
currapp onloaded:[
self stdlog: 'Application LOADED'.
].
]
{ #category : #initialization }
DiyaApplicationLauncher >> onloaded: aBlock [
|loader|
running := true.
loader := DiyaDefaultSystemLoader on: target.
loader job: [ DiyaFontManager uniqueInstance loadFonts. ] name: 'Loading fonts...'.
loader job: [ self defineLayout ] name: 'Define layout...'.
loader onloaded: [
node children do:[:c| target addNode: c at: c position].
node := target.
aBlock value.
self launch: self defaultApplication.
]
]
{ #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).
]

View File

@ -2,8 +2,10 @@ Class {
#name : #DiyaApplicationModel,
#superclass : #DiyaSingleton,
#instVars : [
'root',
'am'
'node',
'am',
'target',
'context'
],
#category : #'Diya-Applications'
}
@ -20,30 +22,42 @@ DiyaApplicationModel >> cleanup [
{ #category : #accessing }
DiyaApplicationModel >> context [
^DiyaRendererContext uniqueInstance
^DiyaRenderer
]
{ #category : #initialization }
DiyaApplicationModel >> initialize [
super initialize.
context := DiyaRenderer
]
{ #category : #'as yet unclassified' }
DiyaApplicationModel >> loadNode [
|pseudoRoot|
pseudoRoot := DiyaRootNode new.
pseudoRoot addNode: node.
pseudoRoot processQueue do:[:el|
el process
].
]
{ #category : #accessing }
DiyaApplicationModel >> main [
DiyaApplicationModel >> node [
^ node
]
{ #category : #accessing }
DiyaApplicationModel >> onloaded: aBlock [
self subclassResponsibility
]
{ #category : #accessing }
DiyaApplicationModel >> quit [
node empty.
self cleanup
]
{ #category : #accessing }
DiyaApplicationModel >> root [
^ root
]
{ #category : #accessing }
DiyaApplicationModel >> setup [
self subclassResponsibility
{ #category : #initialization }
DiyaApplicationModel >> target: aNode [
target := aNode.
]

View File

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

View File

@ -13,11 +13,6 @@ DiyaBaseObject >> checkGLError: mark [
].
]
{ #category : #accessing }
DiyaBaseObject >> logError: string [
self stderr nextPutAll: string; cr
]
{ #category : #asserting }
DiyaBaseObject >> shouldNotBeCalled [
^DiyaCoreAPIError signal: 'Should not be called'
@ -30,12 +25,19 @@ DiyaBaseObject >> stderr [
{ #category : #accessing }
DiyaBaseObject >> stderror: string [
self stderr nextPutAll: string; nextPutAll: Character cr asString.
self stderr
nextPutAll: DateAndTime now asString;
nextPutAll: ': ';
nextPutAll: string;
nextPutAll: Character cr asString.
]
{ #category : #accessing }
DiyaBaseObject >> stdlog: string [
self stdout nextPutAll: string;
self stdout
nextPutAll: DateAndTime now asString;
nextPutAll: ': ';
nextPutAll: string;
nextPutAll: Character cr asString.
]

View File

@ -16,9 +16,12 @@ Class {
#category : #'Diya-Runtime'
}
{ #category : #'instance creation' }
DiyaBoot class >> maxFPS [
^60
{ #category : #'class initialization' }
DiyaBoot class >> initialize [
Smalltalk globals at: #DiyaDisplay put: nil.
Smalltalk globals at: #DiyaSystemClock put: nil.
Smalltalk globals at: #DiyaRenderer put: nil.
Smalltalk globals at: #DiyaSystemSettings put: nil.
]
{ #category : #'instance creation' }
@ -31,12 +34,6 @@ DiyaBoot class >> startx [
self uniqueInstance run
]
{ #category : #events }
DiyaBoot >> GLinit. [
OpenGL viewportX: 0 Y:0 W: display w H: display h.
OpenGL enable: GL_TEXTURE_2D.
]
{ #category : #events }
DiyaBoot >> createGLContext [
context := SDL2 glCreateContext: window.
@ -82,7 +79,10 @@ DiyaBoot >> init [
SDL2 SDLGetCurrentDisplayMode: display from:0.
SDL2 showCursor: 0.
DiyaSingleton resetAll.
DiyaFontManager uniqueInstance loadFonts.
Smalltalk globals at: #Display ifAbsentPut:display.
Smalltalk globals at: #DiyaDisplay put:display.
Smalltalk globals at: #DiyaSystemSettings put: DiyaSettings uniqueInstance.
Smalltalk globals at: #DiyaSystemClock put: DiyaClock uniqueInstance.
]
{ #category : #events }
@ -90,24 +90,28 @@ DiyaBoot >> initialize [
display := nil.
window := nil.
context := nil.
clock := DiyaClock uniqueInstance.
clock := DiyaSystemClock.
]
{ #category : #events }
DiyaBoot >> render [
|delta launcher|
DiyaRendererContext uniqueInstance.
|launcher event|
event := SDL_Event new.
launcher := DiyaApplicationLauncher uniqueInstance.
launcher setup.
self GLinit.
"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 target: DiyaRenderer root.
launcher onloaded: [self stdlog: 'Launcher loaded'].
[ launcher running ] whileTrue: [
delta := DiyaClock uniqueInstance delta asMilliSeconds.
launcher delta: delta.
DiyaClock uniqueInstance tick.
launcher main.
SDL2 glSwapWindow: window.
delta := DiyaClock uniqueInstance delta asMilliSeconds.
SDL2 delay: (0 max: (1000/ self class maxFPS) asInteger - delta).
DiyaSystemClock tick.
[(SDL2 pollEvent: event) > 0] whileTrue: [
DiyaRenderer root trigger: (DiyaEvent from: event mapped).
].
DiyaRenderer render.
SDL2 delay:
(0 max:
(1000/ DiyaSystemSettings maxFPS) asInteger - (DiyaSystemClock lapDelta)).
].
]
@ -181,10 +185,8 @@ DiyaBoot >> showSystemInfo [
stream nextPutAll: rinfo name readString; nextPutAll:' '.
].
stream cr.
stream nextPutAll:'Display resolution: ';
nextPutAll:display w asString;
nextPutAll: 'x';
nextPutAll: display h asString; cr.
stream nextPutAll: DiyaDisplay asString; cr.
stream cr.
self stdout nextPutAll: stream contents
]
@ -197,8 +199,11 @@ DiyaBoot >> startx [
"SDL2 glMakeCurrent: window context: context."
self showSystemInfo.
DiyaRendererContext
uniqueInstance display: display;
uniqueInstance
display: display;
window: window;
useProjection: OrthoProjectionMatrix.
Smalltalk globals at: #DiyaRenderer put: DiyaRendererContext uniqueInstance.
self render.
context delete.
window destroy.

View File

@ -39,14 +39,13 @@ DiyaButton >> label [
]
{ #category : #accessing }
DiyaButton >> text: string [
label txt: string.
]
{ #category : #accessing }
DiyaButton >> update [
DiyaButton >> process [
rec extent: self extent.
label position: 0@0.
label extent: self extent.
^true
]
{ #category : #accessing }
DiyaButton >> text: string [
label txt: string.
]

View File

@ -3,14 +3,15 @@ Class {
#superclass : #DiyaSingleton,
#instVars : [
'monotonic',
'lastTick'
'lastTick',
'lapTime'
],
#category : #'Diya-Runtime'
}
{ #category : #initialization }
DiyaClock >> delta [
^(DateAndTime now) - lastTick
^ self lapDelta + self lapTime
]
{ #category : #initialization }
@ -22,9 +23,21 @@ DiyaClock >> elapsedTime [
DiyaClock >> initialize [
monotonic := DateAndTime now.
lastTick := monotonic.
lapTime := 0.
]
{ #category : #initialization }
DiyaClock >> lapDelta [
^ ((DateAndTime now) - lastTick) asMilliSeconds
]
{ #category : #initialization }
DiyaClock >> lapTime [
^ lapTime
]
{ #category : #initialization }
DiyaClock >> tick [
lapTime := self lapDelta.
lastTick := DateAndTime now.
]

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

@ -0,0 +1,24 @@
Class {
#name : #DiyaDefaultAppLoader,
#superclass : #DiyaDefaultSystemLoader,
#instVars : [
'label'
],
#category : #'Diya-Applications'
}
{ #category : #initialization }
DiyaDefaultAppLoader >> updateLayout [
super updateLayout.
label ifNil:[
label := node addNode: (DiyaText new) at: (progress position + (0@25)).
label inlineStyle: #xAlign value: #center
].
label extent: (progress extent x) @ 40.
]
{ #category : #scheduling }
DiyaDefaultAppLoader >> updateProgress: name percent: p [
label data: name.
progress percent: p
]

View File

@ -0,0 +1,21 @@
Class {
#name : #DiyaDefaultSystemLoader,
#superclass : #DiyaLoader,
#instVars : [
'progress'
],
#category : #'Diya-Applications'
}
{ #category : #initialization }
DiyaDefaultSystemLoader >> updateLayout [
|xtent|
xtent := DiyaRenderer resolution.
progress ifNil:[progress := node addNode: (DiyaLoadingBar new) at: 20@((xtent y >> 1) - 50)].
progress extent: (xtent x - 40) @ 20.
]
{ #category : #scheduling }
DiyaDefaultSystemLoader >> updateProgress: name percent: p [
progress percent: p
]

View File

@ -0,0 +1,41 @@
Class {
#name : #DiyaDefaultTheme,
#superclass : #DiyaStyleSheet,
#category : #'Diya-UIThemes'
}
{ #category : #define }
DiyaDefaultTheme >> defineGlobal [
self define: #global styles: {
#bgColor -> (Color r: 0.2118 g: 0.2118 b: 0.2118).
#color -> Color white.
#border -> 0.
#fontSize -> 18.
#fontFamily -> DiyaFontManager uniqueInstance defaultFamily.
#textIconFamily -> 'bootstrap-icons'.
#fontStyle -> DiyaFontManager uniqueInstance defaultStyle.
#borderColor -> Color transparent.
#xAlign -> #left.
#yAlign -> #middle.
#iconSize -> 24.
}
]
{ #category : #define }
DiyaDefaultTheme >> defineLoadingBar [
self define: #loadingBar styles: {
#bgColor -> Color red.
#border -> 1.
#borderColor -> Color white.
};
define: #loadingProgress styles: {
#bgColor -> Color white.
}
]
{ #category : #initialization }
DiyaDefaultTheme >> initialize [
super initialize.
self defineGlobal.
self defineLoadingBar.
]

View File

@ -23,16 +23,6 @@ DiyaEllipse class >> rx: rx ry: ry shader: s [
yourself
]
{ #category : #initialization }
DiyaEllipse >> draw [
OpenGL
enable: GL_BLEND;
blendFnWithSfactor: GL_SRC_ALPHA dfactor: GL_ONE_MINUS_SRC_ALPHA.
super draw.
OpenGL
disable: GL_BLEND
]
{ #category : #initialization }
DiyaEllipse >> drawBorder [
"do nothing"
@ -59,6 +49,21 @@ DiyaEllipse >> inner: aPoint [
^ ((((dxy x) ** 2)/(rx**2)) + (((dxy y) ** 2) / (ry**2))) < 1.
]
{ #category : #accessing }
DiyaEllipse >> process [
bbox := Rectangle origin: ((rx negated) @ (ry negated)) corner: (rx @ ry).
{
bbox origin x. bbox origin y. 0.0. 0.0.
bbox origin x. bbox corner y. 0.0. 1.0.
bbox corner x. bbox corner y. 1.0. 1.0.
bbox corner x. bbox corner y. 1.0. 1.0.
bbox corner x. bbox origin y. 1.0. 0.0.
bbox origin x. bbox origin y. 0.0. 0.0.
} doWithIndex: [:e :i| vbuffer at: i put: e].
^true
]
{ #category : #accessing }
DiyaEllipse >> rx [
^ rx
@ -87,21 +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.
]
{ #category : #accessing }
DiyaEllipse >> update [
bbox := Rectangle origin: ((rx negated) @ (ry negated)) corner: (rx @ ry).
{
bbox origin x. bbox origin y. 0.0. 0.0.
bbox origin x. bbox corner y. 0.0. 1.0.
bbox corner x. bbox corner y. 1.0. 1.0.
bbox corner x. bbox corner y. 1.0. 1.0.
bbox corner x. bbox origin y. 1.0. 0.0.
bbox origin x. bbox origin y. 0.0. 0.0.
} doWithIndex: [:e :i| vbuffer at: i put: e].
^true
setUniform: #u_rx value: (rx * (scale x)) ;
setUniform: #u_ry value: (ry * (scale y)) .
]

View File

@ -3,7 +3,8 @@ Class {
#superclass : #DiyaBaseObject,
#instVars : [
'enable',
'mapped'
'mapped',
'target'
],
#category : #'Diya-Events'
}
@ -38,3 +39,13 @@ DiyaEvent >> mapped: anObject [
DiyaEvent >> preventDefault [
enable := false
]
{ #category : #accessing }
DiyaEvent >> target [
^ target
]
{ #category : #accessing }
DiyaEvent >> target: anObject [
target := anObject
]

View File

@ -1,6 +1,9 @@
Class {
#name : #DiyaExampleApp,
#superclass : #DiyaBaseApplication,
#instVars : [
'loader'
],
#category : #'Diya-Applications'
}
@ -9,22 +12,128 @@ DiyaExampleApp >> cleanup [
]
{ #category : #accessing }
DiyaExampleApp >> defineNodes [
|node2 node1 img ell label icon button texture loading|
node := DiyaCompositeNode new.
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|
fmgr := DiyaFontManager uniqueInstance.
#(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)" genPrintableASCII" .
].
DiyaUIThemesManager uniqueInstance currentTheme
define: #text_icon_1 styles: {
#color -> Color orange.
#fontSize -> 24.
#bgColor -> Color transparent.
};
define: #text_icon_2 extend:#text_icon_1 styles: {
#fontSize -> 16.
};
define: #image_view styles: {
#color -> (Color r: 1.0 g:1.0 b:1.0 alpha:1.0 ).
#border -> 3.
#color -> Color white.
#border -> 1.
#bgColor -> Color cyan.
#borderColor -> Color red
};
define: #rect_view extend: #image_view styles: {
#bgColor -> Color transparent.
};
define: #text_view styles: {
#color -> Color green.
#color -> Color orange.
#fontSize -> 16.
#bgColor -> Color transparent.
#xAlign -> #center
@ -36,18 +145,18 @@ DiyaExampleApp >> defineStyleSheet [
define: #ell_view styles: {
#borderColor -> Color red.
#color -> Color white.
#bgColor -> Color cyan.
#border -> 3.
#border -> 2.
};
define: #poly_view styles: {
#borderColor -> Color red.
#color -> Color green.
#border -> 3.
#border -> 1.
#bgColor -> Color transparent.
};
define: #button_view styles: {
#borderColor -> Color red.
#borderColor -> (Color r: 0.051 g: 0.051 b: 0.051).
#color -> Color white.
#bgColor -> Color magenta.
#bgColor -> (Color r: 0.1529 g: 0.1529 b: 0.1529).
#border -> 1.
#yAlign -> #middle.
#xAlign -> #center
@ -55,60 +164,26 @@ DiyaExampleApp >> defineStyleSheet [
]
{ #category : #accessing }
DiyaExampleApp >> main [
DiyaExampleApp >> initialize [
super initialize.
loader := nil
]
{ #category : #accessing }
DiyaExampleApp >> setup [
|node node1 ell label icon button|
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 ifNil: [ loader := DiyaDefaultAppLoader on: target ].
loader job: [ self defineStyleSheet ] name: 'Initializing themes...'.
loader job: [
self defineNodes.
self loadNode.
] name: 'Initializing UI elements...'.
node1 := root addNode: (DiyaRectangle size:100@150 shader: DiyaExampleShader uniqueInstance) at: 300 @ 40.
"node1 rotation: (Float pi / 8.0)."
node1 scale: 1.2@1.2.
node1 on: #(mousebuttondown fingerdown) do:[:e|
label txt: 'Mouse ', (node1 local: e mapped worldPosition) asIntegerPoint asString].
node := root addNode: (DiyaImageView from:'mrsang.png') at: 10 @ 400.
node styleName: #image_view.
node extent:200@200.
node := root addNode: (DiyaRectangle new) at: 10@80.
node styleName: #image_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: 100@300.
ell rotation: Float pi / 6.0.
ell styleName: #ell_view.
"node rotation: Float pi / 2.0."
ell textureNamed:'mrsang.png'.
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 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_1 .
button := root addNode: (DiyaButton text: 'Click me !') at: 240@460.
button extent: 200@40.
button icon:"16rF185"'mrsang.png'.
button styleName: #button_view.
^ root
loader onloaded: [
node children do:[:e|
target addNode: e at: e position.
node := target.
].
aBlock value
].
]

View File

@ -22,11 +22,13 @@ DiyaFFIBase class >> libNames [
{ #category : #accessing }
DiyaFFIBase class >> moduleName [
self libNames do:[:aName|
[
(ExternalAddress loadSymbol: self checkSymbol from: aName) ifNotNil: [
^ aName
]
] on: Error do: [ ]
].
].
DiyaCoreAPIError signal: 'Unable to find FFI library (', self checkSymbol, ')'.
DiyaFFILibNotFound signal: 'Unable to find FFI library (', self checkSymbol, ')'.
]
{ #category : #'library path' }

View File

@ -0,0 +1,5 @@
Class {
#name : #DiyaFFILibNotFound,
#superclass : #DiyaError,
#category : #'Diya-Events'
}

View File

@ -59,8 +59,8 @@ DiyaFontIcon >> lastSeparatorFrom: i [
]
{ #category : #initialization }
DiyaFontIcon >> update [
DiyaFontIcon >> process [
data ifNil: [ ^self ].
bbox := Rectangle origin: 0@0 corner: ((data size) * (self fontSize) ) @ self fontSize.
^ super update.
^ super process.
]

View File

@ -13,13 +13,6 @@ DiyaFontManager class >> cleanUpInstance: singleton [
singleton reset.
]
{ #category : #'as yet unclassified' }
DiyaFontManager class >> searchPaths [
^ {
Smalltalk imageDirectory / 'fonts'
}
]
{ #category : #initialization }
DiyaFontManager >> defaultFamily [
^'Ubuntu'
@ -66,7 +59,7 @@ DiyaFontManager >> loadFace: face [
DiyaFontManager >> loadFile: aFile [
| path face i numfaces |
path := aFile fullName convertToWithConverter: UTF8TextConverter new.
Transcript show: 'Loading font file ', path;cr.
self stdlog: 'Loading font file ', path.
i := 0.
numfaces := nil.
[ face := FreeTypeFace basicNew
@ -74,7 +67,7 @@ DiyaFontManager >> loadFile: aFile [
index: i.
face newFaceFromFile: path index: i.
face loadFields.
Transcript show: 'Loaded font face ', face styleName;cr.
self stdlog: 'Loaded font face ', face styleName.
numfaces ifNil: [ numfaces := face numFaces ].
self loadFace: face.
i := i + 1.
@ -90,7 +83,9 @@ DiyaFontManager >> loadFonts [
{ #category : #initialization }
DiyaFontManager >> loadFonts: force [
force ifTrue:[self reset].
self class searchPaths do:[:path| self loadPath: path].
DiyaSystemSettings fontPaths
select:[:p| p asFileReference exists]
thenDo:[:path| self loadPath: path].
]

View File

@ -20,9 +20,9 @@ DiyaImageIcon >> initialize [
]
{ #category : #accessing }
DiyaImageIcon >> update [
DiyaImageIcon >> process [
|v|
v := self iconSize.
self extent: (v@v).
^super update
^super process
]

View File

@ -1,9 +1,6 @@
Class {
#name : #DiyaImageTex,
#superclass : #OpenGLTexImage2D,
#instVars : [
'path'
],
#pools : [
'OpenGLConstants',
'OpenGLTypes'
@ -11,6 +8,16 @@ Class {
#category : #'Diya-Graphics'
}
{ #category : #'instance creation' }
DiyaImageTex class >> fromDisplay: aRect as: assetName [
^ self new fromDisplay: aRect as: assetName; yourself
]
{ #category : #'instance creation' }
DiyaImageTex class >> fromDisplayAs: assetName [
^ self new fromDisplayAs: assetName; yourself
]
{ #category : #'instance creation' }
DiyaImageTex class >> fromFile: path [
^ self new fromFile: path; yourself
@ -18,35 +25,87 @@ DiyaImageTex class >> fromFile: path [
{ #category : #accessing }
DiyaImageTex >> drop [
OpenGL
"OpenGL
disable: GL_CULL_FACE;
disable: GL_BLEND.
disable: GL_BLEND."
]
{ #category : #conversion }
DiyaImageTex >> flipY [
|buffer size linesize top bottom|
size := self bytesSize.
linesize := width << 2.
buffer := FFIExternalArray externalNewType: GLubyte size: linesize.
LibC memset: buffer getHandle value: 0 size: buffer size.
0 to: (height >> 1) -1 do: [ :line|
top := line * linesize.
bottom := (size - (linesize * (line + 1))).
LibC memCopy: (data getHandle) + top to: buffer getHandle size: linesize.
LibC memCopy: (data getHandle) + bottom to: (data getHandle) + top size: linesize.
LibC memCopy: buffer getHandle to: (data getHandle) + bottom size: linesize.
].
buffer free
]
{ #category : #'instance creation' }
DiyaImageTex >> fromDisplay: aRect as: assetName [
data ifNotNil: [data free].
width := aRect extent x asInteger.
height := aRect extent y asInteger.
commited := false.
data := FFIExternalArray externalNewType: GLubyte size: self bytesSize.
LibC memset: data getHandle value: 0 size: data size.
data autoRelease.
OpenGL readPixelsOn: data getHandle
x: aRect origin x
y: (DiyaDisplay height) - (aRect origin y) - (aRect extent y)
w: aRect extent x
h: aRect extent y
format:GL_RGBA
type: GL_UNSIGNED_BYTE.
name := assetName.
self flipY.
]
{ #category : #'instance creation' }
DiyaImageTex >> fromDisplayAs: assetName [
self fromDisplay: (Rectangle origin: 0@0 extent: DiyaDisplay extent ) as: assetName
]
{ #category : #'instance creation' }
DiyaImageTex >> fromFile: aPath [
|form color index|
path := aPath.
Transcript show: 'Loading texture from ', path fullName;cr.
form := ImageReadWriter formFromFileNamed: path.
data := FFIExternalArray externalNewType: GLubyte size:(form width) * (form height) * 4.
|surface|
self stdlog: 'Loading texture from ', aPath fullName.
data ifNotNil: [ data free ].
name := aPath fullName.
surface := self surfaceFromFile: aPath.
width := surface w.
height := surface h.
data := FFIExternalArray externalNewType: GLubyte size: self bytesSize.
LibC memset: data getHandle value: 0 size: data size.
data autoRelease.
width := form width.
height := form height.
index := 1.
0 to: height -1 do:[:y|
0 to: width - 1 do:[:x|
color := (form colorAt: x@y) as4bytesRGB.
data
at: index put: color first;
at: index + 1 put: (color at: 2);
at: index +2 put: (color at: 3);
at: index + 3 put: color last.
index := index + 4.
LibC memCopy: surface pixels getHandle to: data getHandle size: data size.
SDL2
freeSurface: surface.
commited := false.
self stdlog: 'Loaded ', aPath fullName.
]
].
{ #category : #'instance creation' }
DiyaImageTex >> fromForm: aForm name: aName [
|surface|
name := aName.
data ifNotNil: [ data free ].
surface := self surfaceFromForm: aForm.
width := surface w.
height := surface h.
commited := false.
data := FFIExternalArray externalNewType: GLubyte size: self bytesSize.
LibC memset: data getHandle value: 0 size: data size.
data autoRelease.
LibC memCopy: surface pixels getHandle to: data getHandle size: data size.
SDL2
freeSurface: surface.
]
{ #category : #'instance creation' }
@ -65,20 +124,45 @@ DiyaImageTex >> mipmap [
^false
]
{ #category : #accessing }
DiyaImageTex >> path [
^ path
]
{ #category : #accessing }
DiyaImageTex >> setup [
OpenGL
enable: GL_CULL_FACE;
enable: GL_BLEND;
blendFnWithSfactor: GL_SRC_ALPHA dfactor: GL_ONE_MINUS_SRC_ALPHA.
OpenGLTexture
parameteri: GL_TEXTURE_2D pname: GL_TEXTURE_WRAP_S param: GL_CLAMP_TO_EDGE;
parameteri: GL_TEXTURE_2D pname: GL_TEXTURE_WRAP_T param: GL_CLAMP_TO_EDGE;
parameteri: GL_TEXTURE_2D pname: GL_TEXTURE_MIN_FILTER param: GL_LINEAR;
parameteri: GL_TEXTURE_2D pname: GL_TEXTURE_MAG_FILTER param: GL_LINEAR.
]
{ #category : #conversion }
DiyaImageTex >> surfaceFromFile: aPath [
aPath exists ifFalse: [ ^DiyaCoreAPIError signal:'File not found ', aPath fullName ].
[^ SDL2Image SDLImgLoad: aPath fullName] on: Error do: [
^ self surfaceFromForm: (ImageReadWriter formFromFileNamed: aPath)
].
]
{ #category : #conversion }
DiyaImageTex >> surfaceFromForm: aForm [
|srcSurface destSurface form|
form := aForm asFormOfDepth: 32.
srcSurface :=
SDL2 createRGBSurfaceFromPixels: form bits
width: form width height: form height
depth: 32 pitch: (form width << 2)
rmask: 16r00ff0000
gmask: 16r000ff00
bmask: 16r00000ff
amask: 16rff000000.
destSurface :=
SDL2 createRGBSurfaceFromPixels: srcSurface pixels getHandle
width: form width height: form height
depth: 32 pitch: (form width << 2)
rmask: 16r000000ff
gmask: 16r0000ff00
bmask: 16r00ff0000
amask: 16rff000000.
SDL2 SDLBlitSurface: srcSurface srcRect: nil dest: destSurface dstRect: nil.
SDL2
freeSurface: srcSurface.
^ destSurface
]

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
]
@ -52,18 +52,7 @@ DiyaLabel >> initialize [
]
{ #category : #accessing }
DiyaLabel >> txt [
^ txt
]
{ #category : #accessing }
DiyaLabel >> txt: anObject [
txt data: anObject.
self setDirty
]
{ #category : #accessing }
DiyaLabel >> update [
DiyaLabel >> process [
|offset isize align|
offset := 0.
icon ifNotNil: [
@ -73,7 +62,7 @@ DiyaLabel >> update [
].
txt extent: (extent x - offset) @ (extent y).
"lookahead update"
txt update.
txt process.
align := self getHAlign: offset.
txt position: offset @ ( (self extent y - txt extent y ) >> 1).
@ -83,3 +72,14 @@ DiyaLabel >> update [
^ true
]
{ #category : #accessing }
DiyaLabel >> txt [
^ txt
]
{ #category : #accessing }
DiyaLabel >> txt: anObject [
txt data: anObject.
self setDirty
]

View File

@ -81,6 +81,26 @@ DiyaLine >> inner: aPoint [
^false
]
{ #category : #accessing }
DiyaLine >> process [
|extent|
bbox := (Rectangle origin: from corner: to ).
self position: bbox origin.
extent := bbox extent.
bbox := (Rectangle origin: 0@0 corner: extent ).
vbuffer
at: 1 put: 0.0;
at: 2 put: 0.0;
at: 3 put: 0.0;
at: 4 put: 0.0;
at: 5 put: extent x asFloat;
at: 6 put: extent y asFloat;
at: 7 put: 0.0;
at: 8 put: 0.0.
^true
]
{ #category : #accessing }
DiyaLine >> to [
^ to
@ -91,20 +111,3 @@ DiyaLine >> to: anObject [
to := anObject.
self setDirty
]
{ #category : #accessing }
DiyaLine >> update [
|extent|
bbox := (Rectangle origin: from corner: to ).
bbox origin = translation ifFalse:[self position: bbox origin].
from := from - bbox origin.
to := to - bbox origin.
extent := bbox extent.
bbox := (Rectangle origin: 0@0 corner: extent ).
{
0.0. 0.0. 0.0. 0.0.
extent x. extent y. 0.0. 0.0.
} doWithIndex: [:e :i| vbuffer at: i put: e].
^true
]

81
Diya/DiyaLoader.class.st Normal file
View File

@ -0,0 +1,81 @@
Class {
#name : #DiyaLoader,
#superclass : #DiyaBaseObject,
#instVars : [
'node',
'jobs',
'target'
],
#category : #'Diya-Applications'
}
{ #category : #'instance creation' }
DiyaLoader class >> on: target [
^ self new target: target; yourself
]
{ #category : #scheduling }
DiyaLoader >> executeJobs: callback [
"target visibility: false."
target empty.
target addNode: node.
"target visibility: true".
node visibility: true.
self updateLayout.
500 milliSeconds wait.
self job: [ 500 milliSeconds wait. ] name: 'finishing' .
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.
node visibility: false.
target empty.
callback value.
target visibility: true.
]
{ #category : #initialization }
DiyaLoader >> initialize [
super initialize.
node := DiyaCompositeNode new.
jobs := OrderedCollection new.
target := nil.
]
{ #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 : #accessing }
DiyaLoader >> target [
^ target
]
{ #category : #accessing }
DiyaLoader >> target: anObject [
target := anObject
]
{ #category : #initialization }
DiyaLoader >> updateLayout [
self subclassResponsibility
]
{ #category : #scheduling }
DiyaLoader >> updateProgress: name percent: p [
self subclassResponsibility
]

View File

@ -0,0 +1,55 @@
Class {
#name : #DiyaLoadingBar,
#superclass : #DiyaWidget,
#instVars : [
'label',
'bar',
'progress',
'percent'
],
#category : #'Diya-Widgets'
}
{ #category : #accessing }
DiyaLoadingBar >> bar [
^ bar
]
{ #category : #initialization }
DiyaLoadingBar >> initialize [
super initialize.
bar := self addNode: (DiyaRectangle new).
progress := self addNode: (DiyaRectangle new).
bar styleName: #loadingBar.
progress styleName: #loadingProgress.
"label := self addNode: (DiyaLabel new).
label wordWrap: false."
percent := 0.
]
{ #category : #accessing }
DiyaLoadingBar >> label [
^ label
]
{ #category : #accessing }
DiyaLoadingBar >> percent [
^ percent
]
{ #category : #accessing }
DiyaLoadingBar >> percent: anObject [
percent := anObject.
self setDirty.
]
{ #category : #processing }
DiyaLoadingBar >> process [
bar extent: self extent.
progress extent: ((self percent) * (self extent x) / 100) @ (self extent y).
]
{ #category : #accessing }
DiyaLoadingBar >> progress [
^ progress
]

View File

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

View File

@ -10,11 +10,14 @@ Class {
'tf',
'shader',
'context',
'dirty',
'ehandlers',
'root',
'styleName',
'id'
'style',
'inlineStyle',
'id',
'visibility',
'pivot'
],
#pools : [
'OpenGLConstants',
@ -29,32 +32,36 @@ DiyaNode class >> with: shader [
^self new shader: shader; yourself
]
{ #category : #accessing }
DiyaNode >> ? style [
| styles value|
{ #category : #styling }
DiyaNode >> ? styleAttr [
| value|
value := inlineStyle at: styleAttr ifAbsent:[nil].
value ifNotNil: [ ^value ].
styleName ifNotNil: [
styles := DiyaUIThemesManager uniqueInstance currentTheme ? (self styleName).
value := styles at: style ifAbsent:[nil].
style ifNil: [
style := DiyaUIThemesManager uniqueInstance currentTheme ? (self styleName).
].
value := style at: styleAttr ifAbsent:[nil].
value ifNotNil: [ ^value ].
].
"try to look at parent"
parent ifNil:[self styleNotFound: style].
"parent styleName = self styleName ifTrue: [self styleNotFound: style]."
^ parent ? style
"try to look at parent style"
parent ifNil:[self styleNotFound: styleAttr].
^ parent ? styleAttr
]
{ #category : #accessing }
{ #category : #'add/remove' }
DiyaNode >> addNode: node [
^self addNode: node at: 0@0
]
{ #category : #accessing }
{ #category : #'add/remove' }
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
]
@ -68,13 +75,20 @@ DiyaNode >> children [
^children
]
{ #category : #accessing }
{ #category : #rendering }
DiyaNode >> draw [
self subclassResponsibility
]
{ #category : #requirements }
DiyaNode >> empty [
children ifNotNil: [
children do:[:c|
c root: nil.
c setClean.
c visibility: false.
]
].
children := OrderedCollection new.
]
@ -93,23 +107,26 @@ DiyaNode >> initialize [
super initialize.
parent := nil.
shader := nil.
context := DiyaRendererContext uniqueInstance.
context := DiyaRenderer.
children := OrderedCollection new.
dirty := false.
ehandlers := Dictionary new.
styleName := nil.
style := nil.
root := nil.
id := Random new nextInt: 1e6
inlineStyle := Dictionary new.
visibility := true.
pivot := 0@0.
id := self className,'#',(Random new nextInt: 1e6) asString.
]
{ #category : #accessing }
DiyaNode >> inner: aPoint [
^ self subclassResponsibility
{ #category : #styling }
DiyaNode >> inlineStyle: name value: value [
inlineStyle at: name put: value
]
{ #category : #testing }
DiyaNode >> isDirty [
^ dirty
DiyaNode >> inner: aPoint [
^ self subclassResponsibility
]
{ #category : #testing }
@ -134,6 +151,11 @@ DiyaNode >> parent: anObject [
parent := anObject
]
{ #category : #accessing }
DiyaNode >> pivot [
^ pivot
]
{ #category : #accessing }
DiyaNode >> position [
^ translation
@ -145,23 +167,54 @@ DiyaNode >> position: anObject [
self updateTF.
]
{ #category : #processing }
DiyaNode >> process [
^self subclassResponsibility
]
{ #category : #convenience }
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 : #'add/remove' }
DiyaNode >> remove [
parent ifNotNil: [ parent removeChild: self ]
]
{ #category : #'add/remove' }
DiyaNode >> removeChild: c [
c setClean.
c root: nil.
c visibility: false.
children ifNotNil: [ children remove: c ifAbsent:[ ]]
]
{ #category : #rendering }
DiyaNode >> render [
dirty ifTrue:[
dirty := self update not].
visibility ifFalse:[^self].
shader ifNotNil: [self setUpShader].
self draw.
children ifNil: [ ^self ].
children do: [:c | c render ].
root ifNil: [ ^self ].
root renderNext: children
]
{ #category : #'add/remove' }
DiyaNode >> replaceChild: aNode with: anotherNode [
|index|
children ifNil: [ ^ self ].
index := children indexOf: aNode.
index = 0 ifTrue:[^ self].
children at: index put: anotherNode.
anotherNode parent: self.
anotherNode root: self root.
anotherNode setDirtyAll.
aNode root: nil.
]
{ #category : #accessing }
@ -171,7 +224,11 @@ DiyaNode >> root [
{ #category : #accessing }
DiyaNode >> root: anObject [
root := anObject
root = anObject ifTrue:[^self].
root := anObject.
children ifNotNil: [
children do:[:c | c root: root]
]
]
{ #category : #accessing }
@ -185,6 +242,13 @@ DiyaNode >> rotation: anObject [
self updateTF.
]
{ #category : #accessing }
DiyaNode >> rotation: anObject pivot: p [
rotation := anObject.
pivot := p.
self updateTF.
]
{ #category : #accessing }
DiyaNode >> scale [
^ scale
@ -196,25 +260,33 @@ DiyaNode >> scale: anObject [
self updateTF.
]
{ #category : #initialization }
{ #category : #'changing state' }
DiyaNode >> setClean [
dirty := false
root ifNil: [ ^self ].
root cleanDirtyNode: self.
]
{ #category : #initialization }
{ #category : #'changing state' }
DiyaNode >> setDirty [
dirty := true
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.
shader use;
setUniform: #u_time value: DiyaClock uniqueInstance elapsedTime asFloat;
setUniform: #u_time value: DiyaSystemClock elapsedTime asFloat;
setUniform: #u_projection value: {GL_FALSE. context projection buffer};
setUniform: #u_resolution value: { context resolution x. context resolution y };
setUniform: #u_texture value: 0;
setUniform: #u_transform value: {GL_TRUE. mem}.
context mouse ifNotNil: [
"in shader, window origin is bottom left conor of the window
@ -238,6 +310,16 @@ DiyaNode >> shader: anObject [
shader := anObject
]
{ #category : #stepping }
DiyaNode >> step [
]
{ #category : #stepping }
DiyaNode >> stepDown [
self step.
children ifNotNil: [ children do:[:c | c stepDown ] ]
]
{ #category : #accessing }
DiyaNode >> styleName [
^ styleName
@ -246,16 +328,13 @@ DiyaNode >> styleName [
{ #category : #accessing }
DiyaNode >> styleName: anObject [
styleName := anObject.
style := nil.
self setDirty
]
{ #category : #'event handling' }
DiyaNode >> styleNotFound: style [
"looking for default theme in global"
^(DiyaUIThemesManager uniqueInstance defaultTheme ? (self styleName))
at: style ifAbsent:[
DiyaCoreAPIError signal: 'Query undefined style ', style, ' in', styleName.
]
DiyaNode >> styleNotFound: styleAttr [
DiyaCoreAPIError signal: 'Query undefined style ', styleAttr, ' in', styleName.
]
{ #category : #accessing }
@ -266,20 +345,28 @@ DiyaNode >> tf [
{ #category : #'event handling' }
DiyaNode >> trigger: evt [
evt enable ifFalse:[^self].
ehandlers at: evt mapped type ifPresent:[:handler| handler value: evt].
ehandlers at: evt mapped type ifPresent:[:handler|
evt target: self.
handler value: evt].
children ifNil: [^self].
evt enable ifTrue: [
"evt mapped triggableOn: children first."
children select: [:node | evt mapped triggableOn: node ] thenDo:[:node| node trigger: evt]
].
]
{ #category : #accessing }
DiyaNode >> update [
^self subclassResponsibility
]
{ #category : #accessing }
{ #category : #processing }
DiyaNode >> updateTF [
self subclassResponsibility
]
{ #category : #accessing }
DiyaNode >> visibility [
^ visibility
]
{ #category : #accessing }
DiyaNode >> visibility: anObject [
visibility := anObject.
children ifNotNil: [
children do:[:c| c visibility: anObject ] ]
]

View File

@ -41,27 +41,8 @@ DiyaPolygon >> points: anObject [
]
{ #category : #accessing }
DiyaPolygon >> recFromPoints [
|maxX maxY minX minY x y|
maxX := minX := (points at: 1) x.
maxY := minY := (points at: 1) y.
points do: [ :p|
x := p x.
y := p y.
maxX := maxX max: x.
maxY := maxY max: y.
minX := minX min: x.
minY := minY min: y.
].
^ Rectangle origin: minX@minY corner: maxX @ maxY
]
{ #category : #accessing }
DiyaPolygon >> update [
bbox := self recFromPoints.
translation = bbox origin ifFalse:[ self position: bbox origin].
points := points collect:[:e | e - bbox origin].
bbox := self recFromPoints.
DiyaPolygon >> process [
bbox := Rectangle encompassing: points.
self calculateVertices.
^true
]

View File

@ -37,14 +37,28 @@ DiyaRectangle >> initialize [
]
{ #category : #accessing }
DiyaRectangle >> update [
DiyaRectangle >> process [
|extent|
extent := self extent.
{
0. 0. 0.0. 0.0.
0. extent y. 0.0. 1.0.
extent x. extent y. 1.0. 1.0.
extent x. 0. 1.0. 0.0.
} doWithIndex: [:e :i| vbuffer at: i put: e].
vbuffer
at: 1 put: 0.0;
at: 2 put: 0.0;
at: 3 put: 0.0;
at: 4 put: 0.0;
at: 5 put: 0.0;
at: 6 put: extent y asFloat;
at: 7 put: 0.0;
at: 8 put: 1.0;
at: 9 put: extent x asFloat;
at: 10 put: extent y asFloat;
at: 11 put: 1.0;
at: 12 put: 1.0;
at: 13 put: extent x asFloat;
at: 14 put: 0.0;
at: 15 put: 1.0;
at: 16 put: 0.0.
^true
]

View File

@ -6,9 +6,12 @@ Class {
'display',
'vbo',
'vao',
'texture0',
'textures',
'projection',
'assets'
'assets',
'window',
'root',
'lock'
],
#pools : [
'OpenGLConstants',
@ -28,6 +31,11 @@ DiyaRendererContext class >> maxFloatBufferSize [
^4096
]
{ #category : #accessing }
DiyaRendererContext class >> maxTextureNumber [
^ 32
]
{ #category : #accessing }
DiyaRendererContext >> assets [
^ assets
@ -40,9 +48,11 @@ DiyaRendererContext >> assets: anObject [
{ #category : #accessing }
DiyaRendererContext >> destroy [
vao disableAttribute: 0.
vao delete.
vbo delete.
texture0 delete.
textures do: [:e | e key delete ].
textures := OrderedCollection new.
]
{ #category : #accessing }
@ -55,16 +65,42 @@ DiyaRendererContext >> display: anObject [
display := anObject
]
{ #category : #rendering }
DiyaRendererContext >> findTextureUnit [
textures withIndexDo: [ :e :i|
e value ifNil: [ ^ i - 1]
].
"random unit value"
^ (Random new nextInt: self class maxTextureNumber) - 1
]
{ #category : #accessing }
DiyaRendererContext >> initialize [
super initialize.
vbo := OpenGLVertexBuffer new.
vao := OpenGLVertexArray new.
texture0 := OpenGLTexture fromUnit: 0.
textures := Dictionary new.
lock := Mutex new.
vao bind.
vbo bind: GL_ARRAY_BUFFER.
projection := Array2D identity: 4.
assets := AssetManager new.
vao enableAttribute: 0.
OpenGLVertexArray
vertexAttributePointerIndex: 0
size:4
type: GL_FLOAT
normalized: GL_FALSE
stride: 16
pointer: nil.
textures :=
(1 to: self class maxTextureNumber ) collect:[:i|
(OpenGLTexture fromUnit: i - 1) -> nil] .
]
{ #category : #accessing }
DiyaRendererContext >> lock [
^ lock
]
{ #category : #accessing }
@ -82,27 +118,62 @@ DiyaRendererContext >> projection [
^ projection
]
{ #category : #'as yet unclassified' }
{ #category : #rendering }
DiyaRendererContext >> render [
root render.
root readyForSwap ifTrue: [
SDL2 glSwapWindow: window.
]
]
{ #category : #accessing }
DiyaRendererContext >> resolution [
^ (display w) @ (display h)
]
{ #category : #accessing }
DiyaRendererContext >> texture0 [
^ texture0
DiyaRendererContext >> root [
root ifNil: [ root := DiyaRootNode new ].
^ root
]
{ #category : #'as yet unclassified' }
{ #category : #rendering }
DiyaRendererContext >> submitData: vbuffer [
vbo data: GL_ARRAY_BUFFER data: vbuffer usage: GL_STATIC_DRAW.
]
{ #category : #'transformation matrices' }
DiyaRendererContext >> useProjection: aClass [
projection := aClass fromDisplay: self display
]
{ #category : #accessing }
DiyaRendererContext >> vao [
^ vao
{ #category : #rendering }
DiyaRendererContext >> useTexture: aTexture [
|assoc|
aTexture unit == -1 ifTrue:[ aTexture unit: self findTextureUnit].
assoc := textures at: aTexture unit + 1.
assoc value = aTexture ifFalse:[
"unregister current texture"
assoc value ifNotNil: [ assoc value commited: false ].
aTexture commited: false.
assoc value: aTexture.
].
assoc key active.
aTexture commited ifTrue:[ ^ self ].
"self stdlog: 'Commit data data to texture ', aTexture name, ' on Unit ', aTexture unit asString."
assoc key setImage2D: aTexture.
aTexture commited: true.
]
{ #category : #accessing }
DiyaRendererContext >> vbo [
^ vbo
DiyaRendererContext >> window [
^ window
]
{ #category : #accessing }
DiyaRendererContext >> window: anObject [
window := anObject
]

View File

@ -1,6 +1,10 @@
Class {
#name : #DiyaRootNode,
#superclass : #DiyaNode,
#instVars : [
'Q',
'R'
],
#category : #'Diya-Graphics'
}
@ -9,13 +13,22 @@ DiyaRootNode >> boundingBox [
^ Rectangle origin: 0@0 corner: context resolution
]
{ #category : #'add/remove' }
DiyaRootNode >> cleanDirtyNode: aNode [
Q remove: aNode ifAbsent:[]
]
{ #category : #accessing }
DiyaRootNode >> draw [
|c|
c := self ? #bgColor.
OpenGL clearColorR: c red G: c green B: c blue A: c alpha.
OpenGL clear: GL_COLOR_BUFFER_BIT.
context vbo bind: GL_ARRAY_BUFFER.
]
{ #category : #'add/remove' }
DiyaRootNode >> enqueueDirtyNode: aNode [
Q addIfNotPresent: aNode
]
{ #category : #accessing }
@ -29,10 +42,12 @@ DiyaRootNode >> initialize [
parent := self.
shader := nil.
root := self.
styleName := #global
styleName := #global.
Q := OrderedCollection new.
R := OrderedCollection new.
]
{ #category : #'as yet unclassified' }
{ #category : #accessing }
DiyaRootNode >> inner: aPoint [
^true
]
@ -43,8 +58,68 @@ DiyaRootNode >> isRoot [
]
{ #category : #initialization }
DiyaRootNode >> update [
^true
DiyaRootNode >> process [
]
{ #category : #controlling }
DiyaRootNode >> processQueue [
^ Q
]
{ #category : #testing }
DiyaRootNode >> readyForSwap [
^ R isEmpty
]
{ #category : #rendering }
DiyaRootNode >> render [
| maxProcessingTime|
self stepDown.
R ifEmpty: [
self draw.
self renderNext: children
].
maxProcessingTime := (1000 / DiyaSystemSettings maxFPS) asInteger.
[
self spinOnce: maxProcessingTime
] whileTrue
]
{ #category : #rendering }
DiyaRootNode >> renderNext: nodes [
R addAllFirstUnlessAlreadyPresent: nodes.
]
{ #category : #initialization }
DiyaRootNode >> setClean [
]
{ #category : #initialization }
DiyaRootNode >> setDirty [
]
{ #category : #rendering }
DiyaRootNode >> spinOnce: maxProcessingTime [
|node|
Q ifNotEmpty: [
node := Q removeFirst.
node process.
"context lock critical: [node process]."
].
R ifNotEmpty: [
node := R removeFirst.
node render.
"context lock critical: [node render]. "
].
(Q isEmpty and: R isEmpty) ifTrue: [ ^false ].
DiyaSystemSettings renderAtOnce ifTrue: [ ^ true ].
^(DiyaSystemClock lapDelta < maxProcessingTime)
]
{ #category : #accessing }

View File

@ -0,0 +1,90 @@
Class {
#name : #DiyaSettings,
#superclass : #DiyaSingleton,
#instVars : [
'maxFPS',
'fontPaths',
'assetPath',
'renderAtOnce'
],
#category : #'Diya-Core'
}
{ #category : #'as yet unclassified' }
DiyaSettings class >> defaultSettingFile [
^ Smalltalk imageDirectory / 'settings.json'
]
{ #category : #accessing }
DiyaSettings >> assetPath [
^ assetPath
]
{ #category : #accessing }
DiyaSettings >> assetPath: anObject [
assetPath := anObject
]
{ #category : #accessing }
DiyaSettings >> fontPaths [
^ fontPaths
]
{ #category : #accessing }
DiyaSettings >> fontPaths: anObject [
fontPaths := anObject
]
{ #category : #initialization }
DiyaSettings >> initialize [
super initialize.
maxFPS := 60.
renderAtOnce := false.
fontPaths := { Smalltalk imageDirectory / 'fonts' }.
assetPath := Smalltalk imageDirectory / 'assets'.
self loadFromFile.
self logSettings
]
{ #category : #initialization }
DiyaSettings >> loadFromFile [
|d v|
self class defaultSettingFile exists ifFalse: [
self stderror: 'Setting file not found. Using default settings'.
^self
].
d := STON fromStream: self class defaultSettingFile readStream.
maxFPS := d at:'max_fps' ifAbsent:[maxFPS].
v := d at:'asset_dir' ifAbsent:[nil].
v ifNotNil: [ assetPath := v ].
renderAtOnce := d at: 'render_all_at_once' ifAbsent:[renderAtOnce ].
fontPaths := fontPaths , (d at:'font_dirs' ifAbsent:[#()]).
]
{ #category : #initialization }
DiyaSettings >> logSettings [
self stdlog: 'max_fps = ', maxFPS asString.
self stdlog: 'font_dirs = ', fontPaths asString.
self stdlog: 'asset_dir = ', assetPath asString.
self stdlog: 'render_all_at_once = ', renderAtOnce asString.
]
{ #category : #accessing }
DiyaSettings >> maxFPS [
^ maxFPS
]
{ #category : #accessing }
DiyaSettings >> maxFPS: anObject [
maxFPS := anObject
]
{ #category : #accessing }
DiyaSettings >> renderAtOnce [
^ renderAtOnce
]
{ #category : #accessing }
DiyaSettings >> renderAtOnce: anObject [
renderAtOnce := anObject
]

View File

@ -25,7 +25,7 @@ DiyaSingleton class >> new [
{ #category : #'instance creation' }
DiyaSingleton class >> reset [
|singleton key|
key := self class asString asSymbol.
key := self class.
singleton := singletons at: key ifAbsent: [ ^ self ].
self cleanUpInstance: singleton.
singletons removeKey: key
@ -38,11 +38,11 @@ DiyaSingleton class >> resetAll [
{ #category : #'instance creation' }
DiyaSingleton class >> uniqueInstance [
^singletons at: self class asString asSymbol ifAbsentPut: [ super new ].
^singletons at: self class ifAbsentPut: [ super new ].
]
{ #category : #initialization }
DiyaSingleton >> initialize [
super initialize.
Transcript show: 'Initialise unique instance of ', self className; cr.
self stdlog: 'Initialise unique instance of ', self className.
]

41
Diya/DiyaStyle.class.st Normal file
View File

@ -0,0 +1,41 @@
Class {
#name : #DiyaStyle,
#superclass : #DiyaBaseObject,
#instVars : [
'parent',
'style'
],
#category : #'Diya-UIThemes'
}
{ #category : #accessing }
DiyaStyle >> at: name ifAbsent: aBlock [
|value|
value := style at: name ifAbsent:[nil].
value ifNotNil: [ ^value ].
parent ifNil: [ ^aBlock value ].
^ parent at:name ifAbsent: aBlock.
]
{ #category : #accessing }
DiyaStyle >> at: name put: value [
style at: name put: value
]
{ #category : #initialization }
DiyaStyle >> initialize [
super initialize.
style := Dictionary new.
parent := nil
]
{ #category : #accessing }
DiyaStyle >> parent [
^ parent
]
{ #category : #accessing }
DiyaStyle >> parent: anObject [
parent := anObject
]

View File

@ -4,20 +4,32 @@ Class {
#instVars : [
'stylesheet'
],
#category : #'Diya-Graphics'
#category : #'Diya-UIThemes'
}
{ #category : #convenience }
DiyaStyleSheet >> ? sheet [
^stylesheet at: sheet ifAbsent:[
DiyaCoreAPIError signal: 'Unable to query stylesheet ', sheet
DiyaStyleSheet >> ? styleName [
^stylesheet at: styleName ifAbsent:[
DiyaCoreAPIError signal: 'Unable to query stylesheet ', styleName
].
]
{ #category : #initialization }
DiyaStyleSheet >> define: name styles: styles [
stylesheet at: name put: styles asDictionary.
^self
DiyaStyleSheet >> define: styName extend: parentStyName styles: rules [
|parentSheet style|
parentSheet := self ? parentStyName.
style := self define: styName styles: rules.
style parent: parentSheet.
^style
]
{ #category : #initialization }
DiyaStyleSheet >> define: name styles: rules [
|style|
style := rules asDiyaStyle.
stylesheet at: name put: style.
^style
]

View File

@ -101,7 +101,7 @@ DiyaText >> fontStyle [
^ self ? #fontStyle
]
{ #category : #accessing }
{ #category : #'text-processing' }
DiyaText >> formatText [
|offset index line|
lines ifNil: [^self].
@ -176,7 +176,7 @@ DiyaText >> initialize [
maxLineWidth := 0.
]
{ #category : #'as yet unclassified' }
{ #category : #'text-processing' }
DiyaText >> lastSeparatorFrom: index [
index to: 1 by: -1 do: [:i|
(data at: i) isSeparator ifTrue:[^i].
@ -200,6 +200,19 @@ DiyaText >> maxLineWidth [
^ maxLineWidth
]
{ #category : #initialization }
DiyaText >> process [
bbox ifNil: [ ^true ].
data ifNil:[^true].
data ifEmpty:[^true].
texture ifNil: [ self initTexture ].
vbuffer ifNotNil: [vbuffer free].
vbuffer := FFIExternalArray externalNewType: GLfloat size: data size * 16.
vbuffer autoRelease.
self drawText.
^true
]
{ #category : #accessing }
DiyaText >> splitLines [
|line ret tex2D|
@ -214,27 +227,23 @@ DiyaText >> splitLines [
] whileTrue.
]
{ #category : #accessing }
DiyaText >> texture [
texture ifNil: [ self initTexture ].
texheight = texture height ifFalse: [
{ #category : #stepping }
DiyaText >> step [
texture ifNil: [ ^self ].
texheight = texture height ifTrue: [ ^self].
texheight := texture height.
self update.
self setClean.
].
^texture
self setDirty
]
{ #category : #initialization }
DiyaText >> update [
bbox ifNil: [ ^true ].
data ifNil:[^true].
data ifEmpty:[^true].
vbuffer ifNotNil: [vbuffer free].
vbuffer := FFIExternalArray externalNewType: GLfloat size: data size * 16.
vbuffer autoRelease.
self drawText.
^true
{ #category : #accessing }
DiyaText >> styleName: aName [
super styleName: aName.
texture := nil.
]
{ #category : #accessing }
DiyaText >> texture [
^texture
]
{ #category : #'menu messages' }
@ -252,5 +261,5 @@ DiyaText >> valignText:h [
{ #category : #initialization }
DiyaText >> wordWrap: aBool [
wrap := aBool.
dirty := true
self setDirty
]

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 [
^ DiyaSystemClock delta
]
{ #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
]

View File

@ -5,7 +5,7 @@ Class {
'themes',
'currentThemeName'
],
#category : #'Diya-Graphics'
#category : #'Diya-UIThemes'
}
{ #category : #adding }
@ -37,21 +37,7 @@ DiyaUIThemesManager >> defaultTheme [
{ #category : #initialization }
DiyaUIThemesManager >> defineDefaultTheme [
self addTheme: #default stylesheet: (DiyaStyleSheet new
define: #global styles: {
#bgColor -> (Color r: 0.2118 g: 0.2118 b: 0.2118).
#color -> Color white.
#border -> 0.
#fontSize -> 18.
#fontFamily -> DiyaFontManager uniqueInstance defaultFamily.
#textIconFamily -> 'bootstrap-icons'.
#fontStyle -> DiyaFontManager uniqueInstance defaultStyle.
#borderColor -> Color transparent.
#xAlign -> #left.
#yAlign -> #middle.
#iconSize -> 24.
}
)
self addTheme: #default stylesheet: DiyaDefaultTheme new.
]
{ #category : #initialization }

View File

@ -51,18 +51,16 @@ ImageInitializer >> initializeImage [
do: [ :c |
[ c initialize ]
on: Error
do: [ c = Cursor
ifFalse: [ retryList add: c ] ] ].
do: [ retryList add: c ] ].
retryList
do: [ :c |
Transcript
show: 'CLASS: ' , c asString , ' is not initialized';
cr.
self stdlog: 'CLASS: ' , c asString , ' is not initialized, retry'.
c initialize ].
DiyaSingleton resetAll.
FFIMethodRegistry resetAll.
Smalltalk garbageCollect.
SourceFiles := SourceFileArray new.
"Smalltalk vm parameterAt: 45 put: (Smalltalk vm parameterAt: 44) * 2."
Transcript show: 'Image initialized'; cr.
]

View File

@ -1,5 +1,16 @@
Extension { #name : #LibC }
{ #category : #'*Diya' }
LibC class >> alloc: size [
^self uniqueInstance alloc: size
]
{ #category : #'*Diya' }
LibC >> alloc:size [
^self ffiCall: #(void *malloc(size_t size))
]
{ #category : #'*Diya' }
LibC >> memset:pointer value: value size: size [
^self ffiCall: #(void *memset(void *pointer, int value, size_t size))

View File

@ -0,0 +1,15 @@
Extension { #name : #MatrixTransform2x3 }
{ #category : #'*Diya' }
MatrixTransform2x3 >> asGLBuffer [
|buffer|
buffer := FFIExternalArray externalNewType: #float size: 9.
1 to: 6 do:[:i|
buffer at:i put: (self at:i)].
buffer
at: 7 put: 0;
at: 8 put: 0;
at: 9 put: 1.
buffer autoRelease.
^buffer
]

View File

@ -93,6 +93,11 @@ OpenGL class >> pixelstorei: pname param: param [
^self ffiCall: #(void glPixelStorei( GLenum pname,GLint param))
]
{ #category : #geometry }
OpenGL class >> readPixelsOn: buffer x:x y: y w:w h:h format: fmt type: type [
^ self ffiCall: #(void glReadPixels( GLint x,GLint y,GLsizei w,GLsizei h,GLenum fmt,GLenum type,void * buffer))
]
{ #category : #accessing }
OpenGL class >> vertex3fX:x Y:y Z:z [
^self ffiCall: #(void glVertex3f( GLfloat x,GLfloat y,GLfloat z))

View File

@ -11,6 +11,8 @@ Class {
'GL_ARRAY_BUFFER',
'GL_ARRAY_BUFFER_BINDING',
'GL_ATTACHED_SHADERS',
'GL_BGR',
'GL_BGRA',
'GL_BLEND',
'GL_BLUE',
'GL_BYTE',
@ -115,6 +117,8 @@ OpenGLConstants class >> initCommonConstants [
GL_ALPHA := 16r1906.
GL_RGB := 16r1907.
GL_RGBA := 16r1908.
GL_BGR := 16r80E0.
GL_BGRA := 16r80E1.
GL_LINE_SMOOTH := 16r0B20.
GL_LINE_SMOOTH_HINT := 16r0C52
]

View File

@ -26,7 +26,7 @@ OpenGLFontTex class >> fromFace: face ofSize: size [
^self new fromFace: face ofSize: size; yourself
]
{ #category : #'instance creation' }
{ #category : #processing }
OpenGLFontTex >> blitPixel8: bitmap at: offset size: size [
size = (0@0) ifTrue:[^self].
0 to: size y - 1 do: [ :i|
@ -52,9 +52,9 @@ OpenGLFontTex >> charmap [
{ #category : #accessing }
OpenGLFontTex >> drop [
OpenGL
pixelstorei: GL_UNPACK_ALIGNMENT param: 4;
pixelstorei: GL_UNPACK_ALIGNMENT param: 4";
disable: GL_CULL_FACE;
disable: GL_BLEND.
disable: GL_BLEND".
]
{ #category : #accessing }
@ -67,6 +67,8 @@ OpenGLFontTex >> fromFace: aFace ofSize: size [
|minhang rec iptr charcode w numw|
fontSize := size.
face := aFace.
commited := false.
name := aFace familyName, '@', aFace styleName,'@', size asString.
charmap := Dictionary new.
face setPixelWidth:0 height: self fontSize.
cellw := cellh := minhang := maxbearing := 0.
@ -100,7 +102,7 @@ OpenGLFontTex >> fromFace: aFace ofSize: size [
iptr free.
]
{ #category : #accessing }
{ #category : #processing }
OpenGLFontTex >> genGlyph:c [
|rec offset glyph gsize|
face setPixelWidth:0 height: self fontSize.
@ -122,13 +124,20 @@ OpenGLFontTex >> genGlyph:c [
self reallocateBuffer.
].
].
commited := false.
^glyph
]
{ #category : #processing }
OpenGLFontTex >> genPrintableASCII [
33 to: 126 do: [ :c| self genGlyph: c ]
]
{ #category : #accessing }
OpenGLFontTex >> getGlyph: c [
^(self charmap at: c ifAbsentPut:[self genGlyph:c])
^(self charmap at: c ifAbsentPut:[
self genGlyph:c])
]
{ #category : #initialization }
@ -156,7 +165,7 @@ OpenGLFontTex >> meanww [
^ meanww
]
{ #category : #accessing }
{ #category : #processing }
OpenGLFontTex >> reallocateBuffer [
|newbuffer|
maxrows := maxrows + 4.
@ -169,12 +178,12 @@ OpenGLFontTex >> reallocateBuffer [
]
{ #category : #accessing }
{ #category : #initialization }
OpenGLFontTex >> setup [
OpenGL
enable: GL_CULL_FACE;
"enable: GL_CULL_FACE;
enable: GL_BLEND;
blendFnWithSfactor: GL_SRC_ALPHA dfactor: GL_ONE_MINUS_SRC_ALPHA;
blendFnWithSfactor: GL_SRC_ALPHA dfactor: GL_ONE_MINUS_SRC_ALPHA;"
pixelstorei: GL_UNPACK_ALIGNMENT param: 1.
OpenGLTexture
parameteri: GL_TEXTURE_2D pname: GL_TEXTURE_WRAP_S param: GL_CLAMP_TO_EDGE;

View File

@ -10,7 +10,10 @@ Class {
'border',
'format',
'type',
'data'
'data',
'unit',
'commited',
'name'
],
#pools : [
'OpenGLConstants',
@ -29,6 +32,21 @@ OpenGLTexImage2D >> border: anObject [
border := anObject
]
{ #category : #accessing }
OpenGLTexImage2D >> bytesSize [
^(width * height) << 2
]
{ #category : #accessing }
OpenGLTexImage2D >> commited [
^ commited
]
{ #category : #accessing }
OpenGLTexImage2D >> commited: anObject [
commited := anObject
]
{ #category : #accessing }
OpenGLTexImage2D >> data [
^ data
@ -59,7 +77,7 @@ OpenGLTexImage2D >> drop [
{ #category : #accessing }
OpenGLTexImage2D >> extent [
^ width @ height
^ self width @ self height
]
{ #category : #accessing }
@ -82,6 +100,13 @@ OpenGLTexImage2D >> height: anObject [
height := anObject
]
{ #category : #initialization }
OpenGLTexImage2D >> initialize [
super initialize.
unit := -1.
commited := false
]
{ #category : #accessing }
OpenGLTexImage2D >> internalFormat [
^ internalFormat
@ -107,6 +132,11 @@ OpenGLTexImage2D >> mipmap [
^false
]
{ #category : #accessing }
OpenGLTexImage2D >> name [
^ name
]
{ #category : #accessing }
OpenGLTexImage2D >> setup [
^self subclassResponsibility
@ -132,6 +162,16 @@ OpenGLTexImage2D >> type: anObject [
type := anObject
]
{ #category : #accessing }
OpenGLTexImage2D >> unit [
^ unit
]
{ #category : #accessing }
OpenGLTexImage2D >> unit: anObject [
unit := anObject
]
{ #category : #accessing }
OpenGLTexImage2D >> width [
^ width

View File

@ -51,24 +51,24 @@ OpenGLVertexBuffer class >> subData:target offset: offset size: size data: data
^self ffiCall: #(void glBufferSubData(GLenum target,GLintptr offset,GLsizeiptr size,const void * data))
]
{ #category : #'as yet unclassified' }
{ #category : #initialization }
OpenGLVertexBuffer >> bind: target [
^OpenGLVertexBuffer bind:target buffer: self vertexBufferID
]
{ #category : #'as yet unclassified' }
{ #category : #'accessing - data' }
OpenGLVertexBuffer >> data:target data: data size: size usage: usage [
self bind: target.
"self bind: target."
^OpenGLVertexBuffer bufferData: target size: size data:(data ifNil:[data] ifNotNil: [data getHandle]) usage: usage
]
{ #category : #'as yet unclassified' }
{ #category : #'accessing - data' }
OpenGLVertexBuffer >> data:target data: data usage: usage [
self bind: target.
"self bind: target."
^OpenGLVertexBuffer bufferData: target size: (data size) << 2 data:data getHandle usage: usage
]
{ #category : #'as yet unclassified' }
{ #category : #'add/remove' }
OpenGLVertexBuffer >> delete [
OpenGLVertexBuffer deleteBuffersSize: 1 buffers: vertexBufferID getHandle.
]
@ -81,15 +81,15 @@ OpenGLVertexBuffer >> initialize [
OpenGLVertexBuffer genVertexBuffersSize: 1 buffers: vertexBufferID getHandle
]
{ #category : #'as yet unclassified' }
{ #category : #'accessing - data' }
OpenGLVertexBuffer >> subData:target offset: offset data:data [
self bind: target.
"self bind: target."
^OpenGLVertexBuffer subData: target offset: offset size: (data size) << 2 data: data getHandle
]
{ #category : #'as yet unclassified' }
{ #category : #'accessing - data' }
OpenGLVertexBuffer >> subData:target offset: offset data:data size: size [
self bind: target.
"self bind: target."
^OpenGLVertexBuffer subData: target offset: offset size: size data: data getHandle
]

View File

@ -1,10 +1,5 @@
Extension { #name : #Point }
{ #category : #'*Diya' }
Point >> applyTf: tf [
^(tf +* (self asArray3F)) asPoint
]
{ #category : #'*Diya' }
Point >> asArray3F [
^ self asArray3F: 1.0
@ -14,18 +9,3 @@ Point >> asArray3F [
Point >> asArray3F: z [
^ { self x. self y. z }
]
{ #category : #'*Diya' }
Point >> asGLCoord [
|res|
res := DiyaRendererContext uniqueInstance resolution.
^(self / ( res / 2.0)) + (-1.0@ -1.0).
]
{ #category : #'*Diya' }
Point >> glNormalise [
|res p|
res := DiyaRendererContext uniqueInstance resolution.
p := self / (res/ 2).
^ (p x asFloat) @ (p y asFloat)
]

View File

@ -1,8 +0,0 @@
Extension { #name : #Rectangle }
{ #category : #'*Diya' }
Rectangle >> applyTf: tf [
^ Rectangle
origin: (self origin applyTf: tf)
corner: (self corner applyTf: tf)
]

View File

@ -1,11 +1,28 @@
Extension { #name : #SDL2 }
{ #category : #'*Diya' }
SDL2 class >> SDLAllocFormat: pixel_format [
^ self ffiCall: #(SDL_PixelFormat * SDL_AllocFormat(Uint32 pixel_format))
]
{ #category : #'*Diya' }
SDL2 class >> SDLBlitSurface: src srcRect: srcrect dest: dst dstRect: dstrect [
^ self ffiCall: #(int SDL_UpperBlit(SDL_Surface* src,SDL_Rect* srcrect,SDL_Surface* dst,SDL_Rect* dstrect))
]
{ #category : #'*Diya' }
SDL2 class >> SDLClearError [
^ self ffiCall: #(void SDL_ClearError(void))
]
{ #category : #'*Diya' }
SDL2 class >> SDLFreeFormat: handle [
^ self ffiCall: #(void SDL_FreeFormat(SDL_PixelFormat *handle))
]
{ #category : #'*Diya' }
SDL2 class >> SDLGetCurrentDisplayMode: mode from:index [
^ self ffiCall: #(int SDL_GetCurrentDisplayMode(int index, SDL_DisplayMode* mode))

30
Diya/SDL2Image.class.st Normal file
View File

@ -0,0 +1,30 @@
Class {
#name : #SDL2Image,
#superclass : #DiyaFFIBase,
#pools : [
'SDL2Constants',
'SDL2ConstantsHint',
'SDL2Types'
],
#category : #'Diya-SDL2'
}
{ #category : #'as yet unclassified' }
SDL2Image class >> SDLImgLoad: file [
^ self ffiCall: #(SDL_Surface * IMG_Load(const char *file))
]
{ #category : #accessing }
SDL2Image class >> checkSymbol [
^'IMG_Load'
]
{ #category : #accessing }
SDL2Image class >> libNames [
^#(
'libSDL2_image.so'
'libSDL2_image-2.0.so.0'
'libSDL2_image-2.0.so'
'libSDL2_image-2.0.so.0.2.3'
)
]

View File

@ -25,6 +25,25 @@ SDL_DisplayMode class >> fieldsDesc [
)
]
{ #category : #converting }
SDL_DisplayMode >> asString [
^ 'SDL display: ', self width asString, 'x', self height asString, ' - ', self depth asString, ' bits depth'.
]
{ #category : #'color mapping' }
SDL_DisplayMode >> colormapIfNeededFor: dest [
^ Color colorMapIfNeededFrom: self depth to: dest depth
]
{ #category : #'accessing structure variables' }
SDL_DisplayMode >> depth [
|format depth|
format := SDL2 SDLAllocFormat: self format.
depth := format BitsPerPixel.
SDL2 SDLFreeFormat: format.
^depth
]
{ #category : #'accessing structure variables' }
SDL_DisplayMode >> driverdata [
"This method was automatically generated"
@ -37,6 +56,16 @@ SDL_DisplayMode >> driverdata: anObject [
handle pointerAt: OFFSET_DRIVERDATA put: anObject getHandle.
]
{ #category : #'accessing structure variables' }
SDL_DisplayMode >> extent [
^ self w @ self height
]
{ #category : #other }
SDL_DisplayMode >> forceDisplayUpdate [
]
{ #category : #'accessing structure variables' }
SDL_DisplayMode >> format [
"This method was automatically generated"
@ -61,6 +90,11 @@ SDL_DisplayMode >> h: anObject [
handle signedLongAt: OFFSET_H put: anObject
]
{ #category : #'accessing structure variables' }
SDL_DisplayMode >> height [
^ self h
]
{ #category : #'accessing structure variables' }
SDL_DisplayMode >> refresh_rate [
"This method was automatically generated"
@ -84,3 +118,8 @@ SDL_DisplayMode >> w: anObject [
"This method was automatically generated"
handle signedLongAt: OFFSET_W put: anObject
]
{ #category : #'accessing structure variables' }
SDL_DisplayMode >> width [
^ self w
]

View File

@ -8,6 +8,6 @@ SDL_TouchFingerEvent >> triggableOn: aNode [
{ #category : #'*Diya' }
SDL_TouchFingerEvent >> worldPosition [
|resolution|
resolution := DiyaRendererContext uniqueInstance resolution.
resolution := DiyaRenderer resolution.
^((self x)* (resolution x) ) @ ((self y)* (resolution y)).
]

View File

@ -6,6 +6,17 @@ SDL_Window >> destroy [
handle beNull
]
{ #category : #'*Diya' }
SDL_Window class >> finalizeResourceData: aTuple [
| handle |
handle := aTuple first.
handle isNull ifTrue: [ ^ self ].
self destroyWindow: handle.
handle beNull
]
{ #category : #'*Diya' }
SDL_Window >> warpMouseX:x Y:y [
^self ffiCall: #(void SDL_WarpMouseInWindow(self,int x, int y))

3
Jenkinsfile vendored
View File

@ -20,7 +20,8 @@ pipeline{
{
stage('Build image from SDK') {
steps {
build job: 'Diya-image', propagate: true, wait: true
// build specific multi-branch job on master branch
build job: 'gitea-sync/DiyaSDK/master', propagate: true, wait: true
}
}
}