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

Add assets manager, add support for application launching

This commit is contained in:
DanyLE 2022-03-21 18:03:15 +01:00
parent eba462b9c0
commit 42aeb49947
17 changed files with 436 additions and 121 deletions

View File

@ -0,0 +1,42 @@
Class {
#name : #AssetManager,
#superclass : #DiyaBaseObject,
#instVars : [
'assets',
'base'
],
#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' }
AssetManager >> from: location [
base := location
]
{ #category : #initialization }
AssetManager >> initialize [
super initialize.
assets := Dictionary new.
base := self class defaultAssetLocation
]
{ #category : #'as yet unclassified' }
AssetManager >> name: fileName of: type [
^assets at: fileName ifAbsentPut: [(type fromFile: (base / fileName))].
]
{ #category : #'as yet unclassified' }
AssetManager >> texture: name [
^self name: name of: DiyaImageTex
]

View File

@ -11,7 +11,7 @@ Class {
{ #category : #accessing }
Diya2DNode >> boundingBox [
|rec|
children ifNil: [ ^ Rectangle origin: 0@0 corner: 0@0 ].
children ifEmpty: [ ^ Rectangle origin: 0@0 corner: 0@0 ].
rec := children first boundingBox.
children do:[:c|
rec = c ifFalse:[
@ -95,11 +95,14 @@ Diya2DNode >> setUpShader [
Diya2DNode >> updateTF [
tf := Array2D identity:3.
"translation"
tf := tf +* (Array2D translateMatrix2D: translation).
translation = (0@0) ifFalse:[
tf := tf +* (Array2D translateMatrix2D: translation)].
"rotation"
tf := tf +* (Array2D rotationMatrix2D: rotation ).
rotation = 0 ifFalse:[
tf := tf +* (Array2D rotationMatrix2D: rotation )].
"scale"
tf := tf +* (Array2D scaleMatrix2D: scale).
scale = (1@1) ifFalse:[
tf := tf +* (Array2D scaleMatrix2D: scale)].
self parent isRoot ifFalse: [ tf := self parent tf +* tf ].
children ifNotNil: [
children do:[:c| c updateTF ]].

View File

@ -0,0 +1,95 @@
Class {
#name : #Diya2DNodeStyle,
#superclass : #DiyaNodeStyle,
#instVars : [
'bgcolor',
'color',
'border',
'fontSize',
'fontFamilly',
'borderColor',
'width',
'height'
],
#category : #'Diya-Graphics'
}
{ #category : #accessing }
Diya2DNodeStyle >> bgcolor [
^ bgcolor
]
{ #category : #accessing }
Diya2DNodeStyle >> bgcolor: anObject [
bgcolor := anObject
]
{ #category : #accessing }
Diya2DNodeStyle >> border [
^ border
]
{ #category : #accessing }
Diya2DNodeStyle >> border: anObject [
border := anObject
]
{ #category : #accessing }
Diya2DNodeStyle >> borderColor [
^ borderColor
]
{ #category : #accessing }
Diya2DNodeStyle >> borderColor: anObject [
borderColor := anObject
]
{ #category : #accessing }
Diya2DNodeStyle >> color [
^ color
]
{ #category : #accessing }
Diya2DNodeStyle >> color: anObject [
color := anObject
]
{ #category : #accessing }
Diya2DNodeStyle >> fontFamilly [
^ fontFamilly
]
{ #category : #accessing }
Diya2DNodeStyle >> fontFamilly: anObject [
fontFamilly := anObject
]
{ #category : #accessing }
Diya2DNodeStyle >> fontSize [
^ fontSize
]
{ #category : #accessing }
Diya2DNodeStyle >> fontSize: anObject [
fontSize := anObject
]
{ #category : #accessing }
Diya2DNodeStyle >> height [
^ height
]
{ #category : #accessing }
Diya2DNodeStyle >> height: anObject [
height := anObject
]
{ #category : #accessing }
Diya2DNodeStyle >> width [
^ width
]
{ #category : #accessing }
Diya2DNodeStyle >> width: anObject [
width := anObject
]

View File

@ -107,3 +107,8 @@ Diya2DPrimShape >> texture [
Diya2DPrimShape >> texture: anObject [
texture := anObject
]
{ #category : #accessing }
Diya2DPrimShape >> textureNamed: name [
self texture: (context assets texture: name)
]

View File

@ -0,0 +1,90 @@
Class {
#name : #DiyaApplicationLauncher,
#superclass : #DiyaApplicationModel,
#instVars : [
'currapp',
'txtFPS',
'event',
'running'
],
#category : #'Diya-Applications'
}
{ #category : #initialization }
DiyaApplicationLauncher >> appNode [
^root children first
]
{ #category : #initialization }
DiyaApplicationLauncher >> bindGlobalEvent [
|pointer |
pointer := root addNode: (DiyaCircle r: 10) at: 200@200.
pointer color: Color orange.
pointer borderColor: Color red.
pointer borderWidth: 2.
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|
pointer position: e mapped worldPosition.
DiyaRendererContext uniqueInstance mouse: (e mapped x) @ (e mapped y).
].
]
{ #category : #initialization }
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.
root addNode: (Diya2DNode new) at: 0@10.
txtFPS := root addNode:(DiyaText data: 'tick') at: ( self context resolution x - 80)@40.
txtFPS extent: 80@40.
txtFPS fontSize: 18.
txtFPS color: Color red.
self bindGlobalEvent.
running := true.
self launch: self defaultApplication.
]

View File

@ -0,0 +1,50 @@
Class {
#name : #DiyaApplicationModel,
#superclass : #DiyaSingleton,
#instVars : [
'root',
'am'
],
#category : #'Diya-Applications'
}
{ #category : #accessing }
DiyaApplicationModel >> am [
^ am
]
{ #category : #accessing }
DiyaApplicationModel >> cleanup [
self subclassResponsibility
]
{ #category : #accessing }
DiyaApplicationModel >> context [
^DiyaRendererContext uniqueInstance
]
{ #category : #initialization }
DiyaApplicationModel >> initialize [
super initialize.
am := AssetManager new.
]
{ #category : #accessing }
DiyaApplicationModel >> main [
self subclassResponsibility
]
{ #category : #accessing }
DiyaApplicationModel >> quit [
self cleanup
]
{ #category : #accessing }
DiyaApplicationModel >> root [
^ root
]
{ #category : #accessing }
DiyaApplicationModel >> setup [
self subclassResponsibility
]

View File

@ -0,0 +1,11 @@
Class {
#name : #DiyaBaseApplication,
#superclass : #DiyaApplicationModel,
#category : #'Diya-Applications'
}
{ #category : #initialization }
DiyaBaseApplication >> initialize [
super initialize.
root := Diya2DNode new.
]

View File

@ -2,7 +2,6 @@ Class {
#name : #DiyaBoot,
#superclass : #DiyaSingleton,
#instVars : [
'running',
'window',
'context',
'display',
@ -38,21 +37,6 @@ DiyaBoot >> GLinit. [
OpenGL enable: GL_TEXTURE_2D.
]
{ #category : #events }
DiyaBoot >> bindGlobalEventTo: aNode [
|pointer|
pointer := aNode addNode: (DiyaCircle r: 10) at: 200@200.
pointer color: Color orange.
"pointer borderColor: Color red.
pointer borderWidth: 3."
aNode on: #keydown do:[:e| Transcript show: 'keydown...';cr. running := false.].
aNode on: #quit do: [:e| running := false].
aNode on: #(fingerdown fingermotion mousemotion) do:[:e|
pointer position: e mapped worldPosition.
DiyaRendererContext uniqueInstance mouse: (e mapped x) @ (e mapped y).
].
]
{ #category : #events }
DiyaBoot >> createGLContext [
context := SDL2 glCreateContext: window.
@ -87,69 +71,6 @@ DiyaBoot >> createWindow [
^window
]
{ #category : #events }
DiyaBoot >> exampleNodes: tree [
|root node node1 ell tex txtNode icon|
root := tree addNode: (Diya2DNode new) at: 0@10.
tex := (DiyaImageTex fromFile:Smalltalk imageDirectory / 'assets'/'mrsang.png').
txtNode := root addNode: (DiyaText data: 'Event') at: 10@55.
txtNode color: Color orange.
txtNode extent: 200@40.
node1 := root addNode: (DiyaRectangle size:100@150 shader: DiyaExampleShader uniqueInstance) at: 100 @ 400.
node1 rotation: (Float pi / 8.0).
node1 scale: 1.2@1.2.
node1 on: #mousebuttondown do:[:e| txtNode data: 'Mouse ', (node1 local: e mapped worldPosition) asIntegerPoint asString].
node1 on: #fingerdown do:[:e| txtNode data: 'Mouse ', (node1 local: e mapped worldPosition) asIntegerPoint asString].
node := root addNode: (DiyaRectangle size: 200@200) at: 250 @ 430.
node texture: tex.
node color: (Color r: 1.0 g:1.0 b:1.0 alpha:1.0 ).
node borderColor: Color red.
node borderWidth: 3.0.
"style := DiyaFontManager uniqueInstance style: 'Regular' from:'Ubuntu'.
tex1 := (style textureOf: 18).
style := DiyaFontManager uniqueInstance style: 'Regular' from: 'bootstrap-icons'.
node := root addNode: (DiyaRectangle size: tex1 extent) at: 250 @ 300.
node color: (Color orange).
node texture: tex1.
node borderColor: Color red.
node borderWidth: 3.0."
node := root addNode: (DiyaText data: String loremIpsum) at: 10@400.
node extent: 240@320.
node wordWrap: true.
node := root addNode: (DiyaLine from: 10@620 to: 200@635).
node color: (Color red).
node borderWidth: 2.0.
ell := root addNode: (DiyaEllipse rx:150 ry: 100) at: 320@300.
ell borderColor: Color red.
ell color: Color white.
ell rotation: Float pi / 6.0.
ell borderWidth: 3.0.
"node rotation: Float pi / 2.0."
ell texture: tex.
ell on: #mousebuttondown do:[:e| txtNode data: 'Ellipse clicked', (ell local:e mapped worldPosition) asIntegerPoint asString].
ell on: #fingerdown do:[:e| txtNode data: 'Ellipse clicked', (ell local:e mapped worldPosition) asIntegerPoint asString].
node := root addNode: (DiyaConvexPolygon points:{250@100. 400@250. 450@80. 350@60}).
node color: Color green.
node borderColor: Color red.
node texture: tex.
node borderWidth: 3.0.
icon := root addNode: (DiyaFontIcon data: #(16rF101 16rF155 16rF185 16rF21B 16rF298 16rF254)) at: 10@10.
icon fontSize: 24.
icon color: (Color r: 209/255 g: 66/255 b:245/255 ).
^ root
]
{ #category : #events }
DiyaBoot >> init [
| status |
@ -159,15 +80,13 @@ DiyaBoot >> init [
ifFalse: [ ^ DiyaCoreAPIError signal: SDL2 getErrorMessage ].
display := SDL_DisplayMode externalNew autoRelease.
SDL2 SDLGetCurrentDisplayMode: display from:0.
DiyaRendererContext reset.
DiyaFontManager reset.
OpenGLSL resetShaders.
SDL2 showCursor: 0.
DiyaSingleton resetAll.
DiyaFontManager uniqueInstance loadFonts.
]
{ #category : #events }
DiyaBoot >> initialize [
running := true.
display := nil.
window := nil.
context := nil.
@ -185,28 +104,16 @@ DiyaBoot >> randomColorChannel [
{ #category : #events }
DiyaBoot >> render [
|event root text delta fps|
event := SDL_Event new.
root := DiyaRootNode new.
self exampleNodes: root.
DiyaRenderer uniqueInstance root: root.
text := root addNode:(DiyaText data: 'tick') at: (display w - 80)@40.
text extent: 80@40.
text fontSize: 18.
text color: Color red.
self bindGlobalEventTo: root.
|delta launcher|
DiyaRendererContext uniqueInstance.
launcher := DiyaApplicationLauncher uniqueInstance.
launcher setup.
self GLinit.
[ running ] whileTrue: [
[ launcher running ] whileTrue: [
delta := DiyaClock uniqueInstance delta asMilliSeconds.
fps := ((1000/delta) asInteger).
text data: ('FPS:', fps asString).
launcher delta: delta.
DiyaClock uniqueInstance tick.
[(SDL2 pollEvent: event) > 0] whileTrue: [
root trigger: (DiyaEvent from: event mapped).
].
DiyaRenderer uniqueInstance render.
launcher main.
SDL2 glSwapWindow: window.
delta := DiyaClock uniqueInstance delta asMilliSeconds.
SDL2 delay: (0 max: (1000/ self class maxFPS) asInteger - delta).
@ -244,12 +151,6 @@ DiyaBoot >> run: screenSize app: application [
Smalltalk garbageCollect.
]
{ #category : #events }
DiyaBoot >> setCursorPosition: mappedEvt [
window warpMouseX:((mappedEvt x)* (display w) )
Y: ((mappedEvt y) * (display h))
]
{ #category : #logging }
DiyaBoot >> showSystemInfo [
|stream numdriver rinfo|
@ -295,8 +196,7 @@ DiyaBoot >> startx [
self render.
context delete.
window destroy.
DiyaFontManager reset.
DiyaRendererContext reset.
DiyaSingleton resetAll.
SDL2 quit.
]

View File

@ -0,0 +1,76 @@
Class {
#name : #DiyaExampleApp,
#superclass : #DiyaBaseApplication,
#category : #'Diya-Applications'
}
{ #category : #accessing }
DiyaExampleApp >> cleanup [
]
{ #category : #accessing }
DiyaExampleApp >> main [
]
{ #category : #accessing }
DiyaExampleApp >> setup [
|node node1 ell txtNode icon|
txtNode := root addNode: (DiyaText data: 'Event') at: 10@55.
txtNode color: Color orange.
txtNode extent: 200@40.
node1 := root addNode: (DiyaRectangle size:100@150 shader: DiyaExampleShader uniqueInstance) at: 100 @ 400.
node1 rotation: (Float pi / 8.0).
node1 scale: 1.2@1.2.
node1 on: #(mousebuttondown fingerdown) do:[:e|
txtNode data: 'Mouse ', (node1 local: e mapped worldPosition) asIntegerPoint asString].
node := root addNode: (DiyaImageView from:'mrsang.png') at: 250 @ 430.
node color: (Color r: 1.0 g:1.0 b:1.0 alpha:1.0 ).
node borderColor: Color red.
node borderWidth: 3.0.
node extent:200@200.
"style := DiyaFontManager uniqueInstance style: 'Regular' from:'Ubuntu'.
tex1 := (style textureOf: 18).
style := DiyaFontManager uniqueInstance style: 'Regular' from: 'bootstrap-icons'.
node := root addNode: (DiyaRectangle size: tex1 extent) at: 250 @ 300.
node color: (Color orange).
node texture: tex1.
node borderColor: Color red.
node borderWidth: 3.0."
node := root addNode: (DiyaText data: String loremIpsum) at: 10@400.
node extent: 240@320.
node wordWrap: true.
node := root addNode: (DiyaLine from: 10@620 to: 200@635).
node color: (Color red).
node borderWidth: 2.0.
ell := root addNode: (DiyaEllipse rx:150 ry: 100) at: 320@300.
ell borderColor: Color red.
ell color: Color white.
ell rotation: Float pi / 6.0.
ell borderWidth: 3.0.
"node rotation: Float pi / 2.0."
ell textureNamed:'mrsang.png'.
ell on: #(mousebuttondown fingerdown) do:[:e|
txtNode data: 'Ellipse clicked', (ell local:e mapped worldPosition) asIntegerPoint asString].
node := root addNode: (DiyaConvexPolygon points:{250@100. 400@250. 450@80. 350@60}).
node color: Color green.
node borderColor: Color red.
node textureNamed: 'mrsang.png'.
node borderWidth: 3.0.
icon := root addNode: (DiyaFontIcon data: #(16rF101 16rF155 16rF185 16rF21B 16rF298 16rF254)) at: 10@10.
icon fontSize: 24.
icon color: (Color r: 209/255 g: 66/255 b:245/255 ).
^ root
]

View File

@ -1,6 +1,9 @@
Class {
#name : #DiyaImageTex,
#superclass : #OpenGLTexImage2D,
#instVars : [
'path'
],
#pools : [
'OpenGLConstants',
'OpenGLTypes'
@ -21,8 +24,9 @@ DiyaImageTex >> drop [
]
{ #category : #'instance creation' }
DiyaImageTex >> fromFile: path [
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.
@ -61,6 +65,11 @@ DiyaImageTex >> mipmap [
^false
]
{ #category : #accessing }
DiyaImageTex >> path [
^ path
]
{ #category : #accessing }
DiyaImageTex >> setup [
OpenGL

View File

@ -1,5 +1,16 @@
Class {
#name : #DiyaImageView,
#superclass : #DiyaRectangle,
#category : #'Diya-Widgets'
#category : #'Diya-Graphics'
}
{ #category : #'instance creation' }
DiyaImageView class >> from: assetName [
^self new from: assetName ; yourself
]
{ #category : #'instance creation' }
DiyaImageView >> from: name [
texture := context assets texture: name.
self extent: texture extent
]

View File

@ -57,6 +57,11 @@ DiyaNode >> draw [
self subclassResponsibility
]
{ #category : #requirements }
DiyaNode >> empty [
children := OrderedCollection new.
]
{ #category : #accessing }
DiyaNode >> extent [
^ self subclassResponsibility

View File

@ -0,0 +1,5 @@
Class {
#name : #DiyaNodeStyle,
#superclass : #DiyaBaseObject,
#category : #'Diya-Graphics'
}

View File

@ -7,7 +7,8 @@ Class {
'vbo',
'vao',
'texture0',
'projection'
'projection',
'assets'
],
#pools : [
'OpenGLConstants',
@ -27,6 +28,16 @@ DiyaRendererContext class >> maxFloatBufferSize [
^4096
]
{ #category : #accessing }
DiyaRendererContext >> assets [
^ assets
]
{ #category : #accessing }
DiyaRendererContext >> assets: anObject [
assets := anObject
]
{ #category : #accessing }
DiyaRendererContext >> destroy [
vao delete.
@ -53,6 +64,7 @@ DiyaRendererContext >> initialize [
vao bind.
vbo bind: GL_ARRAY_BUFFER.
projection := Array2D identity: 4.
assets := AssetManager new.
]
{ #category : #accessing }

View File

@ -31,6 +31,11 @@ DiyaSingleton class >> reset [
singletons removeKey: key
]
{ #category : #'instance creation' }
DiyaSingleton class >> resetAll [
self allSubclasses do:[:e| e reset]
]
{ #category : #'instance creation' }
DiyaSingleton class >> uniqueInstance [
^singletons at: self class asString asSymbol ifAbsentPut: [ super new ].

View File

@ -59,6 +59,7 @@ ImageInitializer >> initializeImage [
show: 'CLASS: ' , c asString , ' is not initialized';
cr.
c initialize ].
DiyaSingleton resetAll.
FFIMethodRegistry resetAll.
Smalltalk garbageCollect.
SourceFiles := SourceFileArray new.

View File

@ -88,11 +88,6 @@ OpenGLSL class >> linkProgram:program [
^self ffiCall: #(void glLinkProgram(GLuint program))
]
{ #category : #'as yet unclassified' }
OpenGLSL class >> resetShaders [
self allSubclassesDo: [ :c| c reset ].
]
{ #category : #'as yet unclassified' }
OpenGLSL class >> setShaderSourceFor: shader count: n string: s length: l [
^ self ffiCall: #(void glShaderSource( GLuint shader,GLsizei n,const void* s,const GLint *l))