1
0
mirror of https://github.com/lxsang/Diya-API.git synced 2025-07-17 14:29:52 +02:00

36 Commits

Author SHA1 Message Date
d99d6f3604 Use a single big video buffer for rendering instead of one buffer peer primitive shapes
Some checks reported errors
gitea-sync/Diya-API/pipeline/head Something is wrong with the build of this commit
2022-08-13 23:00:41 +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
c249c2e381 Rework on Graphic styling 2022-08-07 20:43:16 +02:00
6d7ab2dcd6 Merge b8257f7011 2022-08-07 18:17:07 +02:00
b8257f7011 refactory code 2022-08-07 18:15:57 +02:00
fcaadbc185 Update example 2022-08-07 11:37:08 +02:00
4467f61f32 update example 2022-08-07 11:35:34 +02:00
396fd9909d Create Jenkinsfile 2022-08-06 23:48:46 +02:00
5915d86219 Change coordinate to top down, improvement on label rendering 2022-08-06 03:11:36 +02:00
a8b89f19c5 allow to set system resolution using the DIYA_RES environment variable 2022-05-23 12:26:46 +02:00
5058d62876 wip: rework on text rendering (performance is still degraded) 2022-03-24 22:48:41 +01:00
d70df41681 wip: styling support to graphic node 2022-03-23 00:52:15 +01:00
e2adc4f733 Clean up 2022-03-22 21:29:36 +01:00
e99500acca WIP: widgets implementation 2022-03-21 22:39:52 +01:00
91cfa95ef7 minor changes 2022-03-21 19:13:11 +01:00
42aeb49947 Add assets manager, add support for application launching 2022-03-21 18:03:15 +01:00
eba462b9c0 Add bootstrap font icons support 2022-03-21 01:45:21 +01:00
ac764da076 WIP: add support for input events 2022-03-19 02:18:29 +01:00
e2a8bc046c improve font rendering in OpenGL, optimise memory usage 2022-03-17 00:32:19 +01:00
f215eb054f Merge pull request #1 from lxsang/conflict
fix conflict
2022-03-16 21:36:26 +01:00
72 changed files with 2386 additions and 612 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,14 +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
]

View File

@ -0,0 +1,58 @@
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 : #adding }
AssetManager >> addAsset: value [
assets at: value name put: value
]
{ #category : #adding }
AssetManager >> addAssetName: name value: value [
assets at: name put: value
]
{ #category : #'instance creation' }
AssetManager >> from: location [
base := location
]
{ #category : #initialization }
AssetManager >> initialize [
super initialize.
assets := Dictionary new.
base := self class defaultAssetLocation
]
{ #category : #accessing }
AssetManager >> name: name [
^assets at: name.
]
{ #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

@ -2,31 +2,32 @@ Class {
#name : #Diya2DNode,
#superclass : #DiyaNode,
#instVars : [
'color',
'vbuffer',
'bbox'
'voffset'
],
#category : #'Diya-Graphics'
}
{ #category : #accessing }
Diya2DNode >> boundingBox [
^ bbox
|rec|
children ifEmpty: [ ^ Rectangle origin: 0@0 corner: 0@0 ].
rec := children first boundingBox.
children do:[:c|
rec = c ifFalse:[
rec := rec merge: c boundingBox]
].
^rec
]
{ #category : #accessing }
Diya2DNode >> color [
^ color
]
{ #category : #accessing }
Diya2DNode >> color: anObject [
color := anObject
Diya2DNode >> draw [
]
{ #category : #accessing }
Diya2DNode >> extent [
^ bbox extent
^ self boundingBox extent
]
{ #category : #accessing }
@ -38,15 +39,26 @@ Diya2DNode >> height [
Diya2DNode >> initialize [
super initialize.
translation := 0@0.
scale := 1.0@1.0.
rotation := 0.0.
tf := Array2D identity: 3.
scale := 1@1.
rotation := 0.
tf := MatrixTransform2x3 identity .
shader := Diya2DShader uniqueInstance.
color := Color white.
vbuffer := nil.
voffset := 0.
]
{ #category : #'as yet unclassified' }
{ #category : #accessing }
Diya2DNode >> inner: aPoint [
^ self boundingBox containsPoint: (self local: aPoint)
]
{ #category : #accessing }
Diya2DNode >> local: aPoint [
^ self tf globalPointToLocal: aPoint
]
{ #category : #accessing }
Diya2DNode >> recFromBuffer [
|maxX maxY minX minY x y|
maxX := minX := vbuffer at: 1.
@ -62,36 +74,29 @@ Diya2DNode >> recFromBuffer [
^ Rectangle origin: minX@minY corner: maxX @ maxY
]
{ #category : #initialization }
Diya2DNode >> setUpShader [
super setUpShader.
shader setUniform: #u_color value: self color asGL4FArray.
]
{ #category : #accessing }
Diya2DNode >> updateTF [
tf := Array2D identity:3.
tf := MatrixTransform2x3 identity.
"translation"
tf := tf +* (Array2D rows: 3 columns: 3 contents: {
1.0. 0.0. translation x.
0.0. 1.0. translation y.
0.0. 0.0. 1.0
}).
tf setOffset: translation + pivot.
"rotation"
tf := tf +* (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
}).
"scale"
tf := tf +* (Array2D rows: 3 columns: 3 contents:{
scale x. 0.0. 0.0.
0.0. scale y. 0.0.
0.0. 0.0. 1.0
}).
self parent isRoot ifFalse: [ tf := self parent tf +* tf ].
children ifNotNil: [
children do:[:c| c updateTF ]].
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 composedWithLocal: tf ].
children ifNotNil: [children do:[:c| c updateTF ]].
]

View File

@ -4,50 +4,49 @@ Class {
#instVars : [
'texture',
'type',
'border',
'bcolor'
'bbox'
],
#category : #'Diya-Graphics'
}
{ #category : #accessing }
Diya2DPrimShape >> borderColor: c [
bcolor := c
Diya2DPrimShape >> borderWidth [
^ self ? #border
]
{ #category : #accessing }
Diya2DPrimShape >> borderWidth: w [
border := w
Diya2DPrimShape >> boundingBox [
^ 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 setTexture: 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.
OpenGL drawArrays: type first:0 count:((vbuffer size )>> 2 ).
voffset := context submitData: vbuffer.
OpenGL drawArrays: type first: voffset count:((vbuffer size )>> 2 ).
"reset value"
self texture ifNotNil: [self texture drop.].
border > 0 ifTrue: [ self drawBorder ].
context vao disableAttribute: 0.
self borderWidth > 0 ifTrue: [ self drawBorder ].
OpenGL
disable: GL_CULL_FACE;
disable: GL_BLEND.
]
{ #category : #initialization }
Diya2DPrimShape >> drawBorder [
"Diya2DShader uniqueInstance use."
color = bcolor ifFalse:[
shader setUniform: #u_color value: bcolor asGL4FArray;
setUniform: #u_texture_type value: 0.
].
shader setUniform: #u_color value: (self ? #borderColor) asGL4FArray;
setUniform: #u_texture_type value: 1.
OpenGL
lineWidth: border.
lineWidth: self borderWidth.
self drawLines.
OpenGL lineWidth: 1.0.
]
@ -62,23 +61,33 @@ Diya2DPrimShape >> drawLines [
self subclassResponsibility
]
{ #category : #accessing }
Diya2DPrimShape >> extent [
^ bbox extent
]
{ #category : #initialization }
Diya2DPrimShape >> initialize [
super initialize.
texture := nil.
children := nil.
type := GL_TRIANGLES.
border := 0.
bcolor := Color white.
bbox := Rectangle origin: 0@0 corner: 0@0.
]
{ #category : #accessing }
Diya2DPrimShape >> inner: aPoint [
bbox ifNil: [ ^false ].
^ bbox containsPoint: (self local: aPoint)
]
{ #category : #initialization }
Diya2DPrimShape >> setUpShader [
super setUpShader
texture ifNotNil:[
self shader
setUniform: #u_texture_type value: texture format.
].
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]).
]
{ #category : #accessing }
@ -90,3 +99,8 @@ Diya2DPrimShape >> texture [
Diya2DPrimShape >> texture: anObject [
texture := anObject
]
{ #category : #accessing }
Diya2DPrimShape >> textureNamed: name [
self texture: (context assets texture: name)
]

View File

@ -10,17 +10,23 @@ Diya2DShader class >> fragmentShader [
#ifdef GL_ES
precision highp float;
#endif
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
// 2D uniforms
uniform int u_texture_type;
uniform vec4 u_color;
uniform vec4 u_bg_color;
uniform sampler2D u_texture;
varying vec2 texcoord;
void main(void) {
vec4 texcolor = vec4(1,1,1,1);
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);
@ -28,8 +34,16 @@ void main(void) {
// rgba
else if (u_texture_type == 0x1908){
texcolor = texture2D(u_texture, texcoord);
}
vec4 pxcolor = texcolor * u_color;
if(pxcolor.a > 0.0)
{
gl_FragColor = pxcolor;
}
else
{
gl_FragColor = u_bg_color;
}
gl_FragColor = texcolor * u_color;
}'
]
@ -55,6 +69,7 @@ Diya2DShader >> setUpUniforms [
self addUniform: #u_texture of: Uniform1i.
self addUniform: #u_texture_type of: Uniform1i.
self addUniform: #u_color of: Uniform4F.
self addUniform: #u_bg_color of: Uniform4F.
self addUniform: #u_border_color of: Uniform4F.
self addUniform: #u_border of: Uniform1F.
]

View File

@ -0,0 +1,119 @@
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 styleName: #pointer.
root on: #keydown do:[:e| self stdlog: 'keydown...'. running := false.].
root on: #quit do: [:e| running := false].
root on: #(fingerdown fingermotion mousemotion) do:[:e|
pointer position: e mapped worldPosition.
DiyaRendererContext uniqueInstance mouse: (e mapped x) @ (e mapped y).
].
]
{ #category : #initialization }
DiyaApplicationLauncher >> defaultApplication [
^DiyaExampleApp
]
{ #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 context assets: currapp am.
[
self stdlog: 'Loading application'.
currapp root visibility: false.
currapp setup.
self appNode addNode: currapp root.
self process: true.
currapp root visibility: true.
self stdlog: 'Application LOADED'.
] fork.
]
{ #category : #initialization }
DiyaApplicationLauncher >> main [
| fps delta|
delta := DiyaClock uniqueInstance delta asMilliSeconds.
fps := DiyaBoot maxFPS.
delta = 0 ifFalse:[ fps := (1000/ delta) asInteger].
txtFPS data: ('FPS:', fps asString).
[(SDL2 pollEvent: event) > 0] whileTrue: [
root trigger: (DiyaEvent from: event mapped).
].
currapp ifNotNil: [currapp main.].
root stepDown.
self process: false.
root render.
]
{ #category : #initialization }
DiyaApplicationLauncher >> process: force [
|Q node maxProcessingTime|
maxProcessingTime := (1000 / DiyaBoot maxFPS) asInteger >> 1.
Q := root processingQueue.
Q ifEmpty:[^ self].
[
node := Q removeFirst.
node process.
Q isNotEmpty and: (
(DiyaClock uniqueInstance lapDelta asMilliSeconds < maxProcessingTime) or: force)
] whileTrue
]
{ #category : #accessing }
DiyaApplicationLauncher >> running [
^ running
]
{ #category : #initialization }
DiyaApplicationLauncher >> setup [
event := SDL_Event new.
DiyaUIThemesManager uniqueInstance currentTheme
define: #fps_text styles: {
#color -> Color red.
#fontSize -> 18.
#bgColor -> Color transparent.
};
define: #pointer styles: {
#borderColor -> Color red.
#bgColor -> Color orange.
#border -> 3
}.
root addNode: (DiyaCompositeNode new) at: 0@0.
txtFPS := root addNode:(DiyaText data: '') at: ( self context resolution x - 80)@(self context resolution y - 40).
txtFPS extent: 80@40.
txtFPS styleName: #fps_text.
self bindGlobalEvent.
running := true.
self launch: self defaultApplication.
]

View File

@ -0,0 +1,49 @@
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.
]
{ #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,13 @@
Class {
#name : #DiyaBaseApplication,
#superclass : #DiyaApplicationModel,
#category : #'Diya-Applications'
}
{ #category : #initialization }
DiyaBaseApplication >> initialize [
super initialize.
root := DiyaCompositeNode new.
root styleName: #global.
am := AssetManager new.
]

View File

@ -13,9 +13,9 @@ DiyaBaseObject >> checkGLError: mark [
].
]
{ #category : #accessing }
DiyaBaseObject >> logError: string [
self stderr nextPutAll: string; cr
{ #category : #asserting }
DiyaBaseObject >> shouldNotBeCalled [
^DiyaCoreAPIError signal: 'Should not be called'
]
{ #category : #accessing }
@ -25,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

@ -2,7 +2,6 @@ Class {
#name : #DiyaBoot,
#superclass : #DiyaSingleton,
#instVars : [
'running',
'window',
'context',
'display',
@ -17,6 +16,11 @@ Class {
#category : #'Diya-Runtime'
}
{ #category : #'class initialization' }
DiyaBoot class >> initialize [
Smalltalk globals at: #DiyaDisplay put: nil
]
{ #category : #'instance creation' }
DiyaBoot class >> maxFPS [
^60
@ -41,7 +45,7 @@ DiyaBoot >> GLinit. [
{ #category : #events }
DiyaBoot >> createGLContext [
context := SDL2 glCreateContext: window.
context ifNil: [ ^self error: SDL2 getErrorMessage ].
context ifNil: [ ^DiyaCoreAPIError signal: SDL2 getErrorMessage ].
^context
]
@ -60,7 +64,7 @@ DiyaBoot >> createWindow [
width: display w
height: display h
flags: SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL.
window ifNil: [ ^self error: SDL2 getErrorMessage ].
window ifNil: [ ^DiyaCoreAPIError signal: SDL2 getErrorMessage ].
"handle fullscreen: SDL_WINDOW_FULLSCREEN."
"SDL2 glSetAttribute: SDL_GL_CONTEXT_PROFILE_MASK value: SDL_GL_CONTEXT_PROFILE_ES.
SDL2 glSetAttribute: SDL_GL_CONTEXT_MAJOR_VERSION value: 2.
@ -72,130 +76,66 @@ DiyaBoot >> createWindow [
^window
]
{ #category : #events }
DiyaBoot >> exampleNodes [
|root node style tex|
root := DiyaRootNode new.
tex := (DiyaImageTex fromFile:Smalltalk imageDirectory / 'assets'/'mrsang.png').
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: 'Bold' from:'Ubuntu'.
"style := DiyaFontManager uniqueInstance style: 'Regular' from: 'bootstrap-icons'."
node := root addNode: (DiyaRectangle size: 208@288) at: 250 @ 50.
node color: (Color orange).
node texture: (style textureOf: 48).
node borderColor: Color red.
node borderWidth: 3.0.
node := root addNode: (DiyaRectangle size:100@150 shader: DiyaExampleShader uniqueInstance) at: 20 @ 400.
node rotation: (Float pi / -8.0).
node scale: 1.5@1.5.
node := root addNode: (DiyaText data: String loremIpsum) at: 10@340.
node extent: 250@320.
node wordWrap: true.
node := root addNode: (DiyaLine from: 10@620 to: 200@635).
node color: (Color red).
node borderWidth: 2.0.
node := root addNode: (DiyaCircle r: 100) at: 200@200.
node borderColor: Color red.
node color: Color white.
node borderWidth: 3.0.
node texture: tex.
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.
^ root
]
{ #category : #events }
DiyaBoot >> init [
| status |
SDL2 setHint: 'SDL_RENDER_DRIVER' value: 'opengles2'.
status := SDL2 init: SDL_INIT_EVERYTHING.
status = 0
ifFalse: [ ^ self error: SDL2 getErrorMessage ].
ifFalse: [ ^ DiyaCoreAPIError signal: SDL2 getErrorMessage ].
display := SDL_DisplayMode externalNew autoRelease.
SDL2 SDLGetCurrentDisplayMode: display from:0.
DiyaRendererContext reset.
DiyaFontManager reset.
OpenGLSL resetShaders.
SDL2 showCursor: 0.
Smalltalk globals at: #Display ifAbsentPut:display.
Smalltalk globals at: #DiyaDisplay put:display.
DiyaSingleton resetAll.
DiyaFontManager uniqueInstance loadFonts.
]
{ #category : #events }
DiyaBoot >> initialize [
running := true.
display := nil.
window := nil.
context := nil.
clock := DiyaClock uniqueInstance.
]
{ #category : #events }
DiyaBoot >> processEvent: event [
|mappedEvt|
mappedEvt := event mapped.
mappedEvt type = SDL_KEYDOWN ifTrue: [ Transcript show: 'keydown...';cr. ^running := false. ].
mappedEvt type = SDL_QUIT ifTrue:[ ^running:= false ].
mappedEvt type = SDL_FINGERDOWN ifTrue:[^self setCursorPosition: mappedEvt ].
mappedEvt type = SDL_FINGERMOTION ifTrue:[^self setCursorPosition: mappedEvt ].
mappedEvt type = SDL_MOUSEMOTION ifTrue:[DiyaRendererContext uniqueInstance mouse: (mappedEvt x) @ (mappedEvt y)].
mappedEvt free.
]
{ #category : #events }
DiyaBoot >> randomColorChannel [
| rand |
rand := Random new.
rand := (rand next) * 255.
rand := rand asInteger.
^ rand
]
{ #category : #events }
DiyaBoot >> render [
|event root text delta fps|
event := SDL_Event new.
root := self exampleNodes.
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.
|launcher|
DiyaRendererContext uniqueInstance.
launcher := DiyaApplicationLauncher uniqueInstance.
launcher setup.
self GLinit.
[ running ] whileTrue: [
delta := DiyaClock uniqueInstance delta asMilliSeconds.
fps := ((1000/delta) asInteger).
text data: ('FPS:', fps asString).
[ launcher running ] whileTrue: [
DiyaClock uniqueInstance tick.
[(SDL2 pollEvent: event) > 0] whileTrue: [
self processEvent: event
].
DiyaRenderer uniqueInstance render.
launcher main.
SDL2 glSwapWindow: window.
delta := DiyaClock uniqueInstance delta asMilliSeconds.
SDL2 delay: (0 max: (1000/ self class maxFPS) asInteger - delta).
SDL2 delay:
(0 max:
(1000/ self class maxFPS) asInteger - (DiyaClock uniqueInstance lapDelta asMilliSeconds)).
].
]
{ #category : #events }
DiyaBoot >> run [
self init.
self startx.
|envar arr|
envar := Smalltalk getenv:'DIYA_RES'.
arr := nil.
envar ifNotNil: [
arr := (envar splitOn: 'x') collect: [ :e| e asInteger ] .
arr size = 2 ifFalse:[
arr := nil.
]
].
arr
ifNil: [
self init.
self startx.
]
ifNotNil: [
self run: (arr at:1) @ (arr at: 2)
]
]
{ #category : #running }
@ -223,12 +163,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|
@ -253,43 +187,27 @@ 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
]
{ #category : #events }
DiyaBoot >> startx [
display ifNil: [ ^self error: 'Please run #init before this method' ].
display ifNil: [ ^DiyaCoreAPIError signal: 'Please run #init before this method' ].
self createWindow.
self createGLContext.
"SDL2 glMakeCurrent: window context: context."
self showSystemInfo.
DiyaRendererContext
uniqueInstance display: display;
useProjection: OrthoProjectionMatrix.
uniqueInstance
display: display;
window: window;
useProjection: OrthoProjectionMatrix.
self render.
context delete.
window destroy.
DiyaFontManager reset.
DiyaRendererContext reset.
DiyaSingleton resetAll.
SDL2 quit.
]
{ #category : #events }
DiyaBoot >> step [
"renderer drawColorR: 0
g: 0
b: 0
a: 255."
OpenGL begin: GL_TRIANGLES.
"draw a simple triangle here"
OpenGL color3fR: 0.1 G:0.2 B: 0.3.
OpenGL vertex3fX: 0 Y: 0 Z: 0.
OpenGL vertex3fX: 1 Y: 0 Z: 0.
OpenGL vertex3fX: 0 Y: 1 Z: 0.
OpenGL end.
]

View File

@ -1,5 +1,51 @@
Class {
#name : #DiyaButton,
#superclass : #DiyaWidget,
#instVars : [
'label',
'rec'
],
#category : #'Diya-Widgets'
}
{ #category : #accessing }
DiyaButton class >> text: string [
^ self new text: string; yourself
]
{ #category : #accessing }
DiyaButton >> icon: ico [
label icon: ico.
label setDirty.
]
{ #category : #accessing }
DiyaButton >> iconSize: size [
label iconSize: size.
]
{ #category : #initialization }
DiyaButton >> initialize [
super initialize.
rec := self addNode: (DiyaRectangle new).
label := self addNode: (DiyaLabel new).
label txt
wordWrap: false.
]
{ #category : #accessing }
DiyaButton >> label [
^ label
]
{ #category : #accessing }
DiyaButton >> process [
rec extent: self extent.
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 asDuration.
]
{ #category : #initialization }
DiyaClock >> lapDelta [
^ ((DateAndTime now) - lastTick)
]
{ #category : #initialization }
DiyaClock >> lapTime [
^ lapTime
]
{ #category : #initialization }
DiyaClock >> tick [
lapTime := (DateAndTime now) - lastTick.
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

@ -11,7 +11,7 @@ DiyaConvexPolygon >> calculateVertices [
vbuffer ifNotNil: [ vbuffer free ].
vbuffer := FFIExternalArray externalNewType: GLfloat size:size.
vbuffer autoRelease.
points sort:[:a :b| a angle < b angle].
points sort:[:a :b| a angle > b angle].
index := 1.
points do:[:point|
texcoord := self texcoordOf: point.
@ -19,7 +19,7 @@ DiyaConvexPolygon >> calculateVertices [
at: index put: point x;
at: index + 1 put: point y;
at: index + 2 put: texcoord x;
at: index + 3 put: 1.0 - texcoord y.
at: index + 3 put: texcoord y.
index := index + 4.
].
p := points at: 2.
@ -28,12 +28,12 @@ DiyaConvexPolygon >> calculateVertices [
at: index put: p x;
at: index + 1 put: p y;
at: index + 2 put: texcoord x;
at: index + 3 put: 1.0 - texcoord y.
at: index + 3 put: texcoord y.
]
{ #category : #initialization }
DiyaConvexPolygon >> drawLines [
OpenGL drawArrays: GL_LINE_LOOP first:0 count: (vbuffer size >> 2) - 1.
OpenGL drawArrays: GL_LINE_LOOP first:voffset count: (vbuffer size >> 2) - 1.
]
{ #category : #initialization }

View File

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

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

@ -24,18 +24,13 @@ DiyaEllipse class >> rx: rx ry: ry shader: s [
]
{ #category : #initialization }
DiyaEllipse >> draw [
OpenGL
enable: GL_BLEND;
blendFnWithSfactor: GL_SRC_ALPHA dfactor: GL_ONE_MINUS_SRC_ALPHA.
super draw.
OpenGL
disable: GL_BLEND
DiyaEllipse >> drawBorder [
"do nothing"
]
{ #category : #initialization }
DiyaEllipse >> drawBorder [
"do nothing"
DiyaEllipse >> drawLines [
self shouldNotBeCalled
]
{ #category : #initialization }
@ -47,6 +42,28 @@ DiyaEllipse >> initialize [
shader := DiyaEllipseShader uniqueInstance.
]
{ #category : #initialization }
DiyaEllipse >> inner: aPoint [
|dxy|
dxy := self local: 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
@ -55,7 +72,7 @@ DiyaEllipse >> rx [
{ #category : #accessing }
DiyaEllipse >> rx: anObject [
rx := anObject.
dirty := true.
self setDirty
]
{ #category : #accessing }
@ -66,30 +83,15 @@ DiyaEllipse >> ry [
{ #category : #accessing }
DiyaEllipse >> ry: anObject [
ry := anObject.
dirty := true
self setDirty
]
{ #category : #initialization }
DiyaEllipse >> setUpShader [
super setUpShader.
self shader
setUniform: #u_border value: border;
setUniform: #u_border_color value: bcolor 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 corner y. 0.0. 0.0.
bbox origin x. bbox origin y. 0.0. 1.0.
bbox corner x. bbox origin y. 1.0. 1.0.
bbox corner x. bbox origin y. 1.0. 1.0.
bbox corner x. bbox corner y. 1.0. 0.0.
bbox origin x. bbox corner y. 0.0. 0.0.
} doWithIndex: [:e :i| vbuffer at: i put: e].
^true
setUniform: #u_border value: (self ? #border);
setUniform: #u_border_color value: ( self ? #borderColor) asGL4FArray;
setUniform: #u_rx value: (rx * (scale x)) ;
setUniform: #u_ry value: (ry * (scale y)) .
]

View File

@ -89,8 +89,8 @@ void draw_ellipse(inout vec4 c, vec2 p, Ellipse e, float border)
vec2 rotate_point(vec2 center, vec2 p,float angle)
{
float s = sin(angle);
float c = cos(angle);
float s = sin(-angle);
float c = cos(-angle);
// translate point back to origin:
p.x -= center.x;
@ -110,7 +110,7 @@ void main() {
vec4 color = vec4(0);
//defining ellipse
Ellipse e = create_ellipse(middle, u_ry, u_rx);
draw_ellipse(color, rotate_point(middle, gl_FragCoord.xy, rotation), e, u_border);
draw_ellipse(color,rotate_point(middle, gl_FragCoord.xy, rotation), e, u_border);
// Output to screen
gl_FragColor = color;
}
@ -125,6 +125,7 @@ precision mediump float;
#endif
uniform mat4 u_projection;
uniform mat3 u_transform;
uniform vec2 u_resolution;
varying float rotation;
varying vec2 middle;
varying vec2 texcoord;
@ -133,7 +134,8 @@ void main()
vec3 coord_global = u_transform * vec3(gl_Vertex.xy, 1.0);
gl_Position = u_projection * vec4(coord_global.xy, 0, 1.0);
rotation = atan(u_transform[1][0], u_transform[0][0]);
middle = (u_transform * vec3(0.0,0.0,1.0)).xy;
vec2 org = (u_transform * vec3(0.0,0.0,1.0)).xy;
middle = vec2(org.x, u_resolution.y - org.y);
texcoord = gl_Vertex.zw;
}'
]

5
Diya/DiyaError.class.st Normal file
View File

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

51
Diya/DiyaEvent.class.st Normal file
View File

@ -0,0 +1,51 @@
Class {
#name : #DiyaEvent,
#superclass : #DiyaBaseObject,
#instVars : [
'enable',
'mapped',
'target'
],
#category : #'Diya-Events'
}
{ #category : #'instance creation' }
DiyaEvent class >> from: mappedEvt [
^ self new mapped: mappedEvt; yourself
]
{ #category : #accessing }
DiyaEvent >> enable [
^ enable
]
{ #category : #initialization }
DiyaEvent >> initialize [
super initialize.
enable := true.
]
{ #category : #accessing }
DiyaEvent >> mapped [
^ mapped
]
{ #category : #accessing }
DiyaEvent >> mapped: anObject [
mapped := anObject
]
{ #category : #initialization }
DiyaEvent >> preventDefault [
enable := false
]
{ #category : #accessing }
DiyaEvent >> target [
^ target
]
{ #category : #accessing }
DiyaEvent >> target: anObject [
target := anObject
]

View File

@ -0,0 +1,170 @@
Class {
#name : #DiyaExampleApp,
#superclass : #DiyaBaseApplication,
#category : #'Diya-Applications'
}
{ #category : #accessing }
DiyaExampleApp >> cleanup [
]
{ #category : #accessing }
DiyaExampleApp >> defineStyleSheet [
|fmgr style|
fmgr := DiyaFontManager uniqueInstance.
#(16 24) do:[:fontSize|
self stdlog: 'Init font size ', fontSize asString, ' of ', fmgr defaultFamily.
style := fmgr style: fmgr defaultStyle from: fmgr defaultFamily.
style textureOf: fontSize.
].
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 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 orange.
#fontSize -> 16.
#bgColor -> Color transparent.
#xAlign -> #center
};
define: #line_view styles: {
#color -> Color red.
#border -> 4
};
define: #ell_view styles: {
#borderColor -> Color red.
#color -> Color white.
#border -> 2.
};
define: #poly_view styles: {
#borderColor -> Color red.
#color -> Color green.
#border -> 1.
#bgColor -> Color transparent.
};
define: #button_view styles: {
#borderColor -> (Color r: 0.051 g: 0.051 b: 0.051).
#color -> Color white.
#bgColor -> (Color r: 0.1529 g: 0.1529 b: 0.1529).
#border -> 1.
#yAlign -> #middle.
#xAlign -> #center
}
]
{ #category : #accessing }
DiyaExampleApp >> main [
]
{ #category : #accessing }
DiyaExampleApp >> setup [
|node node1 img ell label icon button texture loading|
texture := DiyaImageTex new.
"DiyaRendererContext uniqueInstance assets
addAsset:
((Form fromDisplay: ( Rectangle origin: 0@0 corner: 300@300 )) asDiyaTexture: 'display')."
self defineStyleSheet.
label := root addNode: (DiyaLabel new) at: 10@40.
label extent: 250@24.
label styleName:#text_icon_1.
label icon: 16rF254.
"node1 := root addNode: (DiyaRectangle size:100@150 shader: DiyaExampleShader uniqueInstance) at: 300 @ 40.
node1 rotation: 45.
node1 scale: 2.0@2.0.
node1 on: #(mousebuttondown fingerdown) do:[:e|
label txt: 'RECT ', (node1 local: e mapped worldPosition) asIntegerPoint asString]."
img := root addNode: (DiyaImageView from:'mrsang.png') at: 10 @ 400.
img styleName: #image_view.
img extent:200@200.
root on: #(mousebuttondown fingerdown) do:[:e|
"change texture"
|p|
p := e mapped worldPosition.
label txt: 'Mouse ', p asIntegerPoint asString.
DiyaRendererContext uniqueInstance assets
addAsset:(texture fromDisplay: (Rectangle origin: ((p x - 100) @ (p y - 100)) extent: 200@200 ) as: 'capture').
img textureNamed: 'capture'.
].
node := root addNode: (DiyaRectangle new) at: 10@80.
node styleName: #rect_view.
node extent: 240@320.
node := root addNode: (DiyaText data: String loremIpsum) at: 10@80.
node extent: 240@320.
node wordWrap: true.
node styleName: #text_view.
node := root addNode: (DiyaLine from: 10@10 to: 200@200).
node styleName: #line_view.
ell := root addNode: (DiyaEllipse rx:100 ry: 70) at: 120@300.
ell scale: 1.2 @ 1.2.
ell styleName: #ell_view.
"ell rotation: 30."
ell textureNamed:'mrsang.png'.
ell addNode: (DiyaTimerNode timeout: 1000 / 6 do:[:n |
n parent rotation: n parent rotation + 10.
] ).
ell on: #(mousebuttondown fingerdown) do:[:e|
label txt: 'Ellipse clicked', (ell local:e mapped worldPosition) asIntegerPoint asString].
node := root addNode: (DiyaConvexPolygon points:{0@40. 150@190. 200@20. 100@0}) at: 250@60.
node textureNamed: 'mrsang.png'.
node styleName: #poly_view.
icon := root addNode: (DiyaFontIcon data: #(16rF101 16rF155 16rF185 16rF21B 16rF298 16rF254)) at: 240@500.
icon styleName: #text_icon_2.
button := root addNode: (DiyaButton text: 'Click me !') at: 240@460.
icon := DiyaFontIcon data: 16rF130.
"icon := DiyaImageIcon from: 'mrsang.png'."
icon addNode:(DiyaTimerNode timeout: 1000 / 12 do:[:n |
n parent rotation: n parent rotation + 10 pivot: n parent extent / 2.
] ).
button extent: 200@40.
button icon: icon "'mrsang.png'".
"button rotation: Float pi / 2.0."
button styleName: #button_view.
loading := root addNode: (DiyaLoadingBar new) at: 240@550.
loading extent: 200 @ 20.
loading addNode: (DiyaTimerNode timeout: 2000 do:[:n |
|p|
p := (n parent percent + 10).
p > 100 ifTrue:[ p := 0].
n parent percent: p.
] ).
loading := root addNode: (DiyaLoadingBar new) at: 240@580.
loading extent: 200 @ 20.
loading addNode: (DiyaTimerNode timeout: 1000 do:[:n |
|p|
p := (n parent percent + 10).
p > 100 ifTrue:[ p := 0].
n parent percent: p.
] ).
^ root
]

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
].
[
(ExternalAddress loadSymbol: self checkSymbol from: aName) ifNotNil: [
^ aName
]
] on: Error do: [ ]
].
self error: '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

@ -4,7 +4,7 @@ Class {
#instVars : [
'advance',
'bearing',
'texcoord'
'tex'
],
#pools : [
'OpenGLConstants',
@ -34,11 +34,16 @@ DiyaFontGlyph >> bearing: anObject [
]
{ #category : #accessing }
DiyaFontGlyph >> texcoord [
^ texcoord
DiyaFontGlyph >> tex [
^ tex
]
{ #category : #accessing }
DiyaFontGlyph >> texcoord: anObject [
texcoord := anObject
DiyaFontGlyph >> tex: anObject [
tex := anObject
]
{ #category : #accessing }
DiyaFontGlyph >> texcoord [
^ (Rectangle origin: (self origin/ (tex extent) ) asFloatPoint corner: ((self corner) / (tex extent)) asFloatPoint ).
]

View File

@ -0,0 +1,66 @@
Class {
#name : #DiyaFontIcon,
#superclass : #DiyaText,
#pools : [
'FT2Types'
],
#category : #'Diya-Graphics'
}
{ #category : #initialization }
DiyaFontIcon >> data: code [
super data:(code isArray ifTrue: [ code ] ifFalse:[{code}]).
]
{ #category : #initialization }
DiyaFontIcon >> drawText [
|index offset tex glyph |
index := 1.
tex := self texture.
offset := (self alignLine: self fontSize)@(self valignText: self fontSize).
data do: [ :c|
glyph := tex getGlyph: c asInteger.
(self getCharsVerticesFrom: glyph offset: offset cellh: tex cellh) do: [
:e| vbuffer at: index put:e.
index := index + 1
].
"offset setX: offset x + tex spacing setY: offset y"
].
]
{ #category : #accessing }
DiyaFontIcon >> fontName [
^ self ? #textIconFamily
]
{ #category : #initialization }
DiyaFontIcon >> getLinebreakIndices: delta [
self shouldNotBeCalled
]
{ #category : #accessing }
DiyaFontIcon >> iconSize [
^ self fontSize
]
{ #category : #initialization }
DiyaFontIcon >> initialize [
super initialize.
data := { }.
vbuffer := FFIExternalArray externalNewType: GLfloat size:24.
vbuffer autoRelease.
]
{ #category : #initialization }
DiyaFontIcon >> lastSeparatorFrom: i [
self shouldNotBeCalled
]
{ #category : #initialization }
DiyaFontIcon >> process [
data ifNil: [ ^self ].
bbox := Rectangle origin: 0@0 corner: ((data size) * (self fontSize) ) @ self fontSize.
^ super process.
]

View File

@ -22,7 +22,19 @@ DiyaFontManager class >> searchPaths [
{ #category : #initialization }
DiyaFontManager >> defaultFamily [
^self error: 'No font found'
^'Ubuntu'
]
{ #category : #initialization }
DiyaFontManager >> defaultIconSet [
^ self style: 'Regular' from: 'bootstrap-icons'
]
{ #category : #initialization }
DiyaFontManager >> defaultStyle [
^'Regular'
]
@ -62,11 +74,11 @@ 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.
i < numfaces ] whileTrue: [ ]
i < numfaces ] whileTrue
]
{ #category : #initialization }
@ -97,7 +109,7 @@ DiyaFontManager >> reset [
{ #category : #initialization }
DiyaFontManager >> style: styleName from: familyName [
|family|
family := families at: familyName ifAbsent: [ self defaultFamily ].
family := families at: familyName ifAbsent: [ families at: self defaultFamily ].
^family style: styleName
]

View File

@ -1,5 +0,0 @@
Class {
#name : #DiyaIcon,
#superclass : #DiyaImageView,
#category : #'Diya-Widgets'
}

View File

@ -0,0 +1,28 @@
Class {
#name : #DiyaImageIcon,
#superclass : #DiyaImageView,
#category : #'Diya-Graphics'
}
{ #category : #accessing }
DiyaImageIcon >> borderWidth [
^0
]
{ #category : #accessing }
DiyaImageIcon >> iconSize [
^ self ? #iconSize
]
{ #category : #accessing }
DiyaImageIcon >> initialize [
super initialize.
]
{ #category : #accessing }
DiyaImageIcon >> process [
|v|
v := self iconSize.
self extent: (v@v).
^super process
]

View File

@ -1,6 +1,9 @@
Class {
#name : #DiyaImageTex,
#superclass : #OpenGLTexImage2D,
#instVars : [
'name'
],
#pools : [
'OpenGLConstants',
'OpenGLTypes'
@ -8,6 +11,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
@ -15,34 +28,84 @@ 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 >> fromFile: path [
|form color index|
Transcript show: 'Loading texture from ', path fullName;cr.
form := ImageReadWriter formFromFileNamed: path.
data := FFIExternalArray externalNewType: GLubyte size:(form width) * (form height) * 4.
DiyaImageTex >> fromDisplay: aRect as: assetName [
data ifNotNil: [data free].
width := aRect extent x asInteger.
height := aRect extent y asInteger.
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.
]
].
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 [
|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.
LibC memCopy: surface pixels getHandle to: data getHandle size: data size.
SDL2
freeSurface: surface.
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.
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' }
@ -61,15 +124,50 @@ DiyaImageTex >> mipmap [
^false
]
{ #category : #accessing }
DiyaImageTex >> name [
^ name
]
{ #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

@ -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

@ -1,5 +1,85 @@
Class {
#name : #DiyaLabel,
#superclass : #DiyaWidget,
#instVars : [
'txt',
'icon'
],
#category : #'Diya-Widgets'
}
{ #category : #accessing }
DiyaLabel >> fontSize [
^txt fontSize.
]
{ #category : #accessing }
DiyaLabel >> getHAlign: offset [
^ 0 max: (txt alignLine: ( txt maxLineWidth)).
]
{ #category : #accessing }
DiyaLabel >> icon [
^ icon
]
{ #category : #accessing }
DiyaLabel >> icon: anObject [
icon := nil.
anObject isNumber ifTrue: [
icon := self addNode: (DiyaFontIcon data: anObject).].
anObject isString ifTrue: [
icon := self addNode: (DiyaImageIcon from: anObject).
].
icon ifNil: [ icon := self addNode: anObject ].
self setDirty
]
{ #category : #accessing }
DiyaLabel >> iconSize [
icon ifNil: [ ^0 ].
^ icon iconSize
]
{ #category : #initialization }
DiyaLabel >> initialize [
super initialize.
txt := self addNode:(DiyaText data: '').
icon := nil.
self extent: 0@0.
]
{ #category : #accessing }
DiyaLabel >> process [
|offset isize align|
offset := 0.
icon ifNotNil: [
isize := self iconSize.
offset := isize + (isize >> 2).
"icon extent:offset @ (extent y)."
].
txt extent: (extent x - offset) @ (extent y).
"lookahead update"
txt process.
align := self getHAlign: offset.
txt position: offset @ ( (self extent y - txt extent y ) >> 1).
icon ifNil: [ ^self ].
"{ offset. txt extent. txt maxLineWidth. align } inspect."
icon position: (align @( (self extent y - self iconSize ) >> 1)).
^ true
]
{ #category : #accessing }
DiyaLabel >> txt [
^ txt
]
{ #category : #accessing }
DiyaLabel >> txt: anObject [
txt data: anObject.
self setDirty
]

View File

@ -32,17 +32,13 @@ DiyaLine class >> points: points [
yourself
]
{ #category : #accessing }
DiyaLine >> borderColor: c [
color := c
]
{ #category : #initialization }
DiyaLine >> draw [
shader setUniform: #u_texture_type value: 1.
OpenGL
"enable: GL_LINE_SMOOTH;
hint: GL_LINE_SMOOTH_HINT mode: GL_NICEST;"
lineWidth: border.
lineWidth: self borderWidth.
super draw.
OpenGL lineWidth: 1.0";
disable: GL_LINE_SMOOTH".
@ -53,6 +49,11 @@ DiyaLine >> drawBorder [
"do nothing"
]
{ #category : #initialization }
DiyaLine >> drawLines [
self shouldNotBeCalled
]
{ #category : #accessing }
DiyaLine >> from [
^ from
@ -61,7 +62,7 @@ DiyaLine >> from [
{ #category : #accessing }
DiyaLine >> from: anObject [
from := anObject.
dirty := true.
self setDirty
]
{ #category : #initialization }
@ -73,7 +74,31 @@ DiyaLine >> initialize [
vbuffer := FFIExternalArray externalNewType: GLfloat size:8.
vbuffer autoRelease.
type := GL_LINES.
border := 1.0
]
{ #category : #accessing }
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;
at: 6 put: extent y;
at: 7 put: 0.0;
at: 8 put: 0.0.
^true
]
{ #category : #accessing }
@ -84,22 +109,5 @@ DiyaLine >> to [
{ #category : #accessing }
DiyaLine >> to: anObject [
to := anObject.
dirty := true.
]
{ #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
self setDirty
]

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,40 @@
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 : #testing }
DiyaMetaNode >> inner: aPoint [
^ false
]
{ #category : #processing }
DiyaMetaNode >> process [
]
{ #category : #processing }
DiyaMetaNode >> updateTF [
]

View File

@ -10,11 +10,18 @@ Class {
'tf',
'shader',
'context',
'dirty'
'ehandlers',
'root',
'styleName',
'style',
'id',
'visibility',
'pivot'
],
#pools : [
'OpenGLConstants',
'OpenGLTypes'
'OpenGLTypes',
'SDL2Constants'
],
#category : #'Diya-Graphics'
}
@ -24,6 +31,21 @@ DiyaNode class >> with: shader [
^self new shader: shader; yourself
]
{ #category : #accessing }
DiyaNode >> ? styleAttr [
| value|
styleName ifNotNil: [
style ifNil: [
style := DiyaUIThemesManager uniqueInstance currentTheme ? (self styleName).
].
value := style at: styleAttr ifAbsent:[nil].
value ifNotNil: [ ^value ].
].
"try to look at parent style"
parent ifNil:[self styleNotFound: styleAttr].
^ parent ? styleAttr
]
{ #category : #accessing }
DiyaNode >> addNode: node [
^self addNode: node at: 0@0
@ -33,9 +55,11 @@ DiyaNode >> addNode: node [
DiyaNode >> addNode: node at: pos [
children ifNil: [ ^self ].
node parent: self.
node position: pos.
children add: node.
^ node
node position: pos.
node root: self root.
node setDirtyAll.
^ node
]
{ #category : #accessing }
@ -48,16 +72,35 @@ DiyaNode >> children [
^children
]
{ #category : #accessing }
{ #category : #rendering }
DiyaNode >> draw [
self subclassResponsibility
]
{ #category : #requirements }
DiyaNode >> empty [
children := OrderedCollection new.
]
{ #category : #accessing }
DiyaNode >> extent [
^ self subclassResponsibility
]
{ #category : #processing }
DiyaNode >> forceReload [
self process.
children ifNotNil: [
children do:[:c|
c forceReload
]]
]
{ #category : #accessing }
DiyaNode >> id [
^ id
]
{ #category : #initialization }
DiyaNode >> initialize [
super initialize.
@ -65,12 +108,30 @@ DiyaNode >> initialize [
shader := nil.
context := DiyaRendererContext uniqueInstance.
children := OrderedCollection new.
dirty := false
ehandlers := Dictionary new.
styleName := nil.
style := nil.
root := nil.
visibility := true.
pivot := 0@0.
id := self className,'#',(Random new nextInt: 1e6) asString.
]
{ #category : #testing }
DiyaNode >> inner: aPoint [
^ self subclassResponsibility
]
{ #category : #testing }
DiyaNode >> isRoot [
^false
^ false
]
{ #category : #convenience }
DiyaNode >> on: eventName do: aBlock [
eventName isArray ifFalse:[ ^ self register: aBlock to: eventName ].
eventName do:[:e| self register: aBlock to:e ].
]
{ #category : #accessing }
@ -83,6 +144,11 @@ DiyaNode >> parent: anObject [
parent := anObject
]
{ #category : #accessing }
DiyaNode >> pivot [
^ pivot
]
{ #category : #accessing }
DiyaNode >> position [
^ translation
@ -94,13 +160,53 @@ DiyaNode >> position: anObject [
self updateTF.
]
{ #category : #accessing }
{ #category : #processing }
DiyaNode >> process [
^self subclassResponsibility
]
{ #category : #convenience }
DiyaNode >> register: aBlock to: eventName [
|evtCode|
evtCode := SDL2Constants bindingOf: ('SDL_', eventName asUppercase).
evtCode ifNil: [ evtCode := eventName ].
ehandlers at: evtCode value put: aBlock.
]
{ #category : #removing }
DiyaNode >> remove [
self setClean.
root := nil.
parent ifNotNil: [ parent removeChild: self ]
]
{ #category : #removing }
DiyaNode >> removeChild: c [
children ifNotNil: [ children remove: c ifAbsent:[ ]]
]
{ #category : #rendering }
DiyaNode >> render [
dirty ifTrue:[dirty := self update not].
shader ifNotNil: [ self setUpShader ].
visibility ifFalse:[^self].
shader ifNotNil: [self setUpShader].
self draw.
children ifNil: [ ^self ].
children do: [:c | c render ].
children do: [:c| c render ].
]
{ #category : #accessing }
DiyaNode >> root [
^ root
]
{ #category : #accessing }
DiyaNode >> root: anObject [
root = anObject ifTrue:[^self].
root := anObject.
children ifNotNil: [
children do:[:c | c root: root]
]
]
{ #category : #accessing }
@ -114,6 +220,13 @@ DiyaNode >> rotation: anObject [
self updateTF.
]
{ #category : #accessing }
DiyaNode >> rotation: anObject pivot: p [
rotation := anObject.
pivot := p.
self updateTF.
]
{ #category : #accessing }
DiyaNode >> scale [
^ scale
@ -125,7 +238,26 @@ DiyaNode >> scale: anObject [
self updateTF.
]
{ #category : #accessing }
{ #category : #'changing state' }
DiyaNode >> setClean [
root ifNil: [ ^self ].
root cleanDirtyNode: self.
]
{ #category : #'changing state' }
DiyaNode >> setDirty [
root ifNil: [ ^self ].
self root enqueueDirtyNode: self.
]
{ #category : #'changing state' }
DiyaNode >> setDirtyAll [
self setDirty.
children ifNotNil: [
children do:[:c| c setDirtyAll] ]
]
{ #category : #rendering }
DiyaNode >> setUpShader [
|mem|
mem := self tf asGLBuffer.
@ -139,7 +271,7 @@ DiyaNode >> setUpShader [
"in shader, window origin is bottom left conor of the window
the mouse position should be transformed to this coodinate"
shader setUniform: #u_mouse value:
{ context mouse x. context resolution y - context mouse y }.
{ context mouse x. context mouse y }.
].
mem free.
]
@ -157,18 +289,62 @@ 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
]
{ #category : #accessing }
DiyaNode >> styleName: anObject [
styleName := anObject.
style := nil.
self setDirty
]
{ #category : #'event handling' }
DiyaNode >> styleNotFound: styleAttr [
DiyaCoreAPIError signal: 'Query undefined style ', styleAttr, ' in', styleName.
]
{ #category : #accessing }
DiyaNode >> tf [
parent ifNil: [ self error: 'TF: This node is not attached to the main tree' ].
^ tf
]
{ #category : #accessing }
DiyaNode >> update [
^self subclassResponsibility
{ #category : #'event handling' }
DiyaNode >> trigger: evt [
evt enable ifFalse:[^self].
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 }
{ #category : #processing }
DiyaNode >> updateTF [
self subclassResponsibility
]
{ #category : #accessing }
DiyaNode >> visibility [
^ visibility
]
{ #category : #accessing }
DiyaNode >> visibility: anObject [
visibility := anObject
]

View File

@ -37,31 +37,12 @@ DiyaPolygon >> points [
{ #category : #accessing }
DiyaPolygon >> points: anObject [
points := anObject.
dirty := true
self setDirty
]
{ #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

@ -16,17 +16,14 @@ DiyaRectangle class >> size: size shader:s [
{ #category : #initialization }
DiyaRectangle >> drawLines [
self drawLineAt: 0.
self drawLineAt: 1.
self drawLineAt: 3.
self drawLineAt: 4.
OpenGL drawArrays: GL_LINE_LOOP first:voffset count: (vbuffer size >> 2).
]
{ #category : #accessing }
DiyaRectangle >> extent: v [
bbox := Rectangle origin:0@0 corner: v.
dirty := true
self setDirty
]
{ #category : #accessing }
@ -34,22 +31,34 @@ DiyaRectangle >> initialize [
super initialize.
self extent:10@10.
translation := nil.
vbuffer := FFIExternalArray externalNewType: GLfloat size:24.
vbuffer := FFIExternalArray externalNewType: GLfloat size:16.
vbuffer autoRelease.
type := GL_QUADS.
]
{ #category : #accessing }
DiyaRectangle >> update [
DiyaRectangle >> process [
|extent|
extent := self extent.
{
0.0. extent y. 0.0. 0.0.
0. 0. 0.0. 1.0.
extent x. 0.0. 1.0. 1.0.
extent x. 0.0. 1.0. 1.0.
extent x. extent y. 1.0. 0.0.
0.0. extent y. 0.0. 0.0.
} doWithIndex: [:e :i| vbuffer at: i put: e].
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;
at: 7 put: 0.0;
at: 8 put: 1.0;
at: 9 put: extent x;
at: 10 put: extent y;
at: 11 put: 1.0;
at: 12 put: 1.0;
at: 13 put: extent x;
at: 14 put: 0.0;
at: 15 put: 1.0;
at: 16 put: 0.0.
^true
]

View File

@ -1,37 +0,0 @@
Class {
#name : #DiyaRenderer,
#superclass : #DiyaSingleton,
#instVars : [
'root'
],
#pools : [
'OpenGLConstants',
'OpenGLTypes'
],
#category : #'Diya-Graphics'
}
{ #category : #'instance creation' }
DiyaRenderer class >> fromContext: ctx [
^self new context: ctx; yourself
]
{ #category : #initialization }
DiyaRenderer >> initialize [
super initialize.
]
{ #category : #deleting }
DiyaRenderer >> render [
root render.
]
{ #category : #accessing }
DiyaRenderer >> root [
^ root
]
{ #category : #accessing }
DiyaRenderer >> root: anObject [
root := anObject
]

View File

@ -7,7 +7,11 @@ Class {
'vbo',
'vao',
'texture0',
'projection'
'projection',
'assets',
'window',
'vbuffer',
'voffset'
],
#pools : [
'OpenGLConstants',
@ -16,6 +20,11 @@ Class {
#category : #'Diya-Graphics'
}
{ #category : #accessing }
DiyaRendererContext class >> bufferSize [
^ 524288 "512Kb"
]
{ #category : #'instance creation' }
DiyaRendererContext class >> cleanUpInstance: singleton [
singleton ifNil:[^self].
@ -28,12 +37,29 @@ DiyaRendererContext class >> maxFloatBufferSize [
]
{ #category : #accessing }
DiyaRendererContext >> destroy [
DiyaRendererContext >> assets [
^ assets
]
{ #category : #accessing }
DiyaRendererContext >> assets: anObject [
assets := anObject
]
{ #category : #accessing }
DiyaRendererContext >> destroy [
self disableGLAttribute: 0.
vbuffer free.
vao delete.
vbo delete.
texture0 delete.
]
{ #category : #registration }
DiyaRendererContext >> disableGLAttribute: attribute [
vao disableAttribute: attribute
]
{ #category : #accessing }
DiyaRendererContext >> display [
^ display
@ -44,6 +70,11 @@ DiyaRendererContext >> display: anObject [
display := anObject
]
{ #category : #registration }
DiyaRendererContext >> enableGLAttribute: attribute [
vao enableAttribute: attribute.
]
{ #category : #accessing }
DiyaRendererContext >> initialize [
super initialize.
@ -53,6 +84,15 @@ DiyaRendererContext >> initialize [
vao bind.
vbo bind: GL_ARRAY_BUFFER.
projection := Array2D identity: 4.
assets := AssetManager new.
"allocate vbuffer"
vbuffer := FFIExternalArray externalNewType: GLfloat size: self class bufferSize.
vbuffer autoRelease.
voffset := 0.
vbo data: GL_ARRAY_BUFFER data: vbuffer usage: GL_STREAM_DRAW.
self enableGLAttribute: 0.
OpenGLVertexArray vertexAttributePointerIndex: 0 size:4 type: GL_FLOAT normalized: GL_FALSE stride: 16 pointer: nil.
]
{ #category : #accessing }
@ -70,17 +110,42 @@ DiyaRendererContext >> projection [
^ projection
]
{ #category : #'as yet unclassified' }
{ #category : #registration }
DiyaRendererContext >> resetBuffer [
voffset := 0
]
{ #category : #accessing }
DiyaRendererContext >> resolution [
^ (display w) @ (display h)
]
{ #category : #registration }
DiyaRendererContext >> setTexture: texture [
texture setup.
texture0 setImage2D: texture.
texture0 active.
]
{ #category : #registration }
DiyaRendererContext >> submitData: data [
|n|
n := self voffset.
voffset := voffset + (data size << 2).
voffset > self class bufferSize ifTrue:[
^ DiyaCoreAPIError signal: 'Out of video buffer memory'
].
vbo subData: GL_ARRAY_BUFFER offset: n data: data.
^ (n >> 4)
]
{ #category : #accessing }
DiyaRendererContext >> texture0 [
^ texture0
]
{ #category : #'as yet unclassified' }
{ #category : #registration }
DiyaRendererContext >> useProjection: aClass [
projection := aClass fromDisplay: self display
]
@ -94,3 +159,23 @@ DiyaRendererContext >> vao [
DiyaRendererContext >> vbo [
^ vbo
]
{ #category : #accessing }
DiyaRendererContext >> vbuffer [
^ vbuffer
]
{ #category : #accessing }
DiyaRendererContext >> voffset [
^ voffset
]
{ #category : #accessing }
DiyaRendererContext >> window [
^ window
]
{ #category : #accessing }
DiyaRendererContext >> window: anObject [
window := anObject
]

View File

@ -1,14 +1,45 @@
Class {
#name : #DiyaRootNode,
#superclass : #DiyaNode,
#instVars : [
'Q'
],
#category : #'Diya-Graphics'
}
{ #category : #accessing }
DiyaRootNode >> Q [
^ Q
]
{ #category : #accessing }
DiyaRootNode >> boundingBox [
^ Rectangle origin: 0@0 corner: context resolution
]
{ #category : #'add/remove' }
DiyaRootNode >> cleanDirtyNode: aNode [
Q remove: aNode ifAbsent:[]
]
{ #category : #accessing }
DiyaRootNode >> draw [
OpenGL clearColorR: 0.0 G: 0.0 B: 0.0 A:0.
|c|
context resetBuffer.
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.
"context vbo bind: GL_ARRAY_BUFFER."
]
{ #category : #'add/remove' }
DiyaRootNode >> enqueueDirtyNode: aNode [
(Q includes: aNode ) ifFalse:[ Q add: aNode].
]
{ #category : #accessing }
DiyaRootNode >> extent [
^ context resolution
]
{ #category : #initialization }
@ -16,16 +47,42 @@ DiyaRootNode >> initialize [
super initialize.
parent := self.
shader := nil.
root := self.
styleName := #global.
Q := OrderedCollection new
]
{ #category : #testing }
DiyaRootNode >> isRoot [
^ true
{ #category : #accessing }
DiyaRootNode >> inner: aPoint [
^true
]
{ #category : #accessing }
DiyaRootNode >> isRoot [
^true
]
{ #category : #initialization }
DiyaRootNode >> update [
^true
DiyaRootNode >> process [
]
{ #category : #accessing }
DiyaRootNode >> processingQueue [
^ Q
]
{ #category : #initialization }
DiyaRootNode >> setClean [
]
{ #category : #initialization }
DiyaRootNode >> setDirty [
]
{ #category : #accessing }

View File

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

View File

@ -19,7 +19,7 @@ DiyaSingleton class >> initialize [
{ #category : #'instance creation' }
DiyaSingleton class >> new [
self error: 'Use #uniqueInstance'
^ DiyaCoreAPIError signal: 'Use #uniqueInstance'
]
{ #category : #'instance creation' }
@ -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 ].
@ -39,5 +44,5 @@ DiyaSingleton class >> uniqueInstance [
{ #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

@ -0,0 +1,45 @@
Class {
#name : #DiyaStyleSheet,
#superclass : #DiyaBaseObject,
#instVars : [
'stylesheet'
],
#category : #'Diya-UIThemes'
}
{ #category : #convenience }
DiyaStyleSheet >> ? styleName [
^stylesheet at: styleName ifAbsent:[
DiyaCoreAPIError signal: 'Unable to query stylesheet ', styleName
].
]
{ #category : #initialization }
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
]
{ #category : #initialization }
DiyaStyleSheet >> initialize [
super initialize.
stylesheet := Dictionary new.
]
{ #category : #accessing }
DiyaStyleSheet >> stylesheet [
^ stylesheet
]

View File

@ -1,5 +1,5 @@
Class {
#name : #DiyaTableLayout,
#superclass : #DiyaWidget,
#superclass : #DiyaLayout,
#category : #'Diya-Widgets'
}

View File

@ -1,13 +1,13 @@
Class {
#name : #DiyaText,
#superclass : #Diya2DNode,
#superclass : #Diya2DPrimShape,
#instVars : [
'fontStyle',
'fontSize',
'fontName',
'data',
'style',
'wrap'
'wrap',
'texheight',
'font',
'lines',
'maxLineWidth'
],
#pools : [
'FT2Types'
@ -25,6 +25,34 @@ DiyaText class >> data: string shader: s [
^ (self with:s) data: string; yourself
]
{ #category : #'menu messages' }
DiyaText >> align [
^ self ? #xAlign
]
{ #category : #accessing }
DiyaText >> alignLine:w [
self align = #center ifTrue:[^ 0 max:((self extent x - w) / 2.0 ) asFloat].
self align = #right ifTrue:[^ 0 max: self extent x - w].
^0
]
{ #category : #initialization }
DiyaText >> allocMemory [
vbuffer ifNotNil: [
vbuffer size >= data size
ifTrue: [^self]
ifFalse:[vbuffer free]
].
vbuffer := FFIExternalArray externalNewType: GLfloat size: data size * 16.
vbuffer autoRelease.
]
{ #category : #accessing }
DiyaText >> borderWidth [
^0
]
{ #category : #accessing }
DiyaText >> data [
^ data
@ -33,146 +61,200 @@ DiyaText >> data [
{ #category : #accessing }
DiyaText >> data: anObject [
data := anObject.
dirty := true
self setDirty
]
{ #category : #accessing }
DiyaText >> draw [
data ifNil: [ ^self ].
self shader
setUniform: #u_texture_type value: self texture format.
"configure vao vbo for texture QUAD"
self texture setup.
context texture0 setImage2D: self texture.
context texture0 active.
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.
OpenGL drawArrays: GL_TRIANGLES first:0 count: ((vbuffer size) >> 2).
context vao disableAttribute: 0.
"reset value"
self texture drop.
{ #category : #initialization }
DiyaText >> drawBorder [
self shouldNotBeCalled
]
{ #category : #initialization }
DiyaText >> drawLines [
^ self shouldNotBeCalled
]
{ #category : #accessing }
DiyaText >> drawText [
|vertices index tex2D offset|
index := 1.
offset := 0@0.
tex2D := self texture.
1 to: data size do: [ :i|
vertices := self getCharsVerticesAt:i offset: offset on: tex2D.
vertices do: [
:e| vbuffer at: index put:e.
index := index + 1.
].
(offset x > self extent x and: wrap not) ifTrue: [ ^self ].
(offset y negated > self extent y) ifTrue: [ ^self ].
].
self splitLines.
self formatText .
]
{ #category : #accessing }
DiyaText >> extent: v [
bbox := Rectangle origin: 0@0 corner: (v x) @ (v y negated ).
dirty := true
self setDirty
]
{ #category : #accessing }
DiyaText >> fontName [
^ fontName
]
{ #category : #initialization }
DiyaText >> fontName: name style: face size: size [
name ifNotNil: [ fontName := name ].
face ifNotNil: [ fontStyle := face ].
fontSize := size.
style := DiyaFontManager uniqueInstance style: self fontStyle from: self fontName.
dirty := true.
^ self ? #fontFamily
]
{ #category : #accessing }
DiyaText >> fontSize [
^ fontSize
]
{ #category : #initialization }
DiyaText >> fontSize: size [
self fontName: nil style:nil size: size
^ self ? #fontSize
]
{ #category : #accessing }
DiyaText >> fontStyle [
^ fontStyle
^ self ? #fontStyle
]
{ #category : #'text-processing' }
DiyaText >> formatText [
|offset index line|
lines ifNil: [^self].
offset := 0@(self valignText: (texture linespace) * (lines size)).
index := 1.
lines do:[:assoc|
line := assoc value.
offset setX: (self alignLine: assoc key) setY: offset y.
line do:[:g|
(self getCharsVerticesFrom: g offset: offset cellh: texture cellh) do:[:v|
vbuffer at: index put:v.
index := index + 1.
]
].
offset setX: 0.0 setY: (offset y ) + (texture linespace)
].
]
{ #category : #accessing }
DiyaText >> getCharsVerticesAt:i offset: offset on: tex2D [
|x y w h glyph gsize c |
c := (data at:i) asciiValue.
c = (Character space asciiValue) ifTrue:[
offset setX: (offset x + (tex2D spacing ) ) setY: offset y.
wrap ifTrue: [
(offset x + ((self nextSpaceFrom: i + 1) * (tex2D fontSize))) > (self extent x) ifTrue: [
offset setX: 0.0 setY: (offset y )- (tex2D linespace)].
].
^ {}.
].
glyph := tex2D getGlyph: c.
DiyaText >> getCharsVerticesFrom:glyph offset: offset cellh: cellh [
|x y w h gsize texcoord|
gsize := glyph extent.
((offset x > self extent x) and: (gsize x > 0)) ifTrue:[
wrap ifFalse: [ ^ { } ].
offset setX: 0.0 setY: (offset y )- (tex2D linespace).
offset y negated > self extent y ifTrue:[^{}].
].
x := offset x + (glyph bearing x).
y := offset y - (tex2D cellh).
y := offset y "- cellh".
w := (gsize x).
h := (gsize y).
texcoord := glyph texcoord.
offset setX: (offset x + (glyph advance x)) setY: offset y.
^{x. y + h. glyph texcoord origin x. glyph texcoord origin y.
x. y. glyph texcoord origin x. glyph texcoord corner y.
x + w. y. glyph texcoord corner x. glyph texcoord corner y.
x. y + h. glyph texcoord origin x. glyph texcoord origin y.
x + w. y. glyph texcoord corner x. glyph texcoord corner y.
x + w. y + h. glyph texcoord corner x. glyph texcoord origin y. }.
^{x. y. texcoord origin x. texcoord origin y.
x. y + h. texcoord origin x. texcoord corner y.
x + w. y + h. texcoord corner x. texcoord corner y.
"x. y + h. texcoord origin x. texcoord origin y.
x + w. y. texcoord corner x. texcoord corner y."
x + w. y. texcoord corner x. texcoord origin y. }.
]
{ #category : #accessing }
DiyaText >> getLineAt: index to: line with: tex2D [
| glyph ret w |
w := 0.
index to: data size do:[ :i|
glyph := tex2D getGlyph: (data at:i) asInteger.
(w + (glyph advance x)) >= (self extent x) ifTrue:[
wrap ifFalse: [ ^ i @ w].
ret := self lastSeparatorFrom: i.
ret to: i - 1 do:[:j|
w := w - (line removeLast advance x)].
^ (ret+1)@w
] ifFalse:[
w := w + (glyph advance x).
line add: glyph.
].
].
maxLineWidth := maxLineWidth max: w.
^ (data size + 1) @ w
]
{ #category : #initialization }
DiyaText >> initTexture [
font:= DiyaFontManager uniqueInstance style: self fontStyle from: self fontName.
texture := font textureOf: self fontSize.
]
{ #category : #initialization }
DiyaText >> initialize [
super initialize.
self fontName: 'Ubuntu' style:'Regular' size: 16.
data := nil.
wrap := false.
bbox := nil
texheight := 0.
type := GL_QUADS.
maxLineWidth := 0.
]
{ #category : #'as yet unclassified' }
DiyaText >> nextSpaceFrom: index [
index to: (data size) do: [:i|
(data at: i) = (Character space) ifTrue:[^i - index].
{ #category : #'text-processing' }
DiyaText >> lastSeparatorFrom: index [
index to: 1 by: -1 do: [:i|
(data at: i) isSeparator ifTrue:[^i].
].
^ 0
]
{ #category : #accessing }
DiyaText >> texture [
^style textureOf: self fontSize
DiyaText >> lines [
^ lines
]
{ #category : #accessing }
DiyaText >> maxLineHeight [
texture ifNil: [ ^0].
^ texture linespace
]
{ #category : #accessing }
DiyaText >> maxLineWidth [
^ maxLineWidth
]
{ #category : #initialization }
DiyaText >> update [
bbox ifNil: [ ^false ].
DiyaText >> process [
bbox ifNil: [ ^true ].
data ifNil:[^true].
data ifEmpty:[^true].
texture ifNil: [ self initTexture ].
texheight = texture height ifFalse: [
texheight := texture height.
].
vbuffer ifNotNil: [vbuffer free].
vbuffer := FFIExternalArray externalNewType: GLfloat size: data size * 24.
vbuffer := FFIExternalArray externalNewType: GLfloat size: data size * 16.
vbuffer autoRelease.
self drawText.
^true
]
{ #category : #accessing }
DiyaText >> splitLines [
|line ret tex2D|
ret := 1@0.
tex2D := self texture.
lines := OrderedCollection new.
[
line := OrderedCollection new.
ret := self getLineAt: ret x to: line with: tex2D.
lines add: ((ret y) -> line).
(ret x < data size) and: wrap
] whileTrue.
]
{ #category : #accessing }
DiyaText >> styleName: aName [
super styleName: aName.
texture := nil.
]
{ #category : #accessing }
DiyaText >> texture [
^texture
]
{ #category : #'menu messages' }
DiyaText >> valign [
^ self ? #yAlign
]
{ #category : #accessing }
DiyaText >> valignText:h [
self valign = #middle ifTrue:[^ (0 max:((self extent y - h) / 2 ) asFloat)].
self valign = #bottom ifTrue:[^ (0 max:(self extent y - h ))].
^0
]
{ #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 [
^ DiyaClock uniqueInstance delta asMilliSeconds
]
{ #category : #accessing }
DiyaTimerNode >> initialize [
super initialize.
elapsedTime := 0.
handlers := OrderedCollection new.
]
{ #category : #'as yet unclassified' }
DiyaTimerNode >> onTimeout: aBlock [
handlers add: aBlock
]
{ #category : #'as yet unclassified' }
DiyaTimerNode >> onceTimeout: aBlock [
|newBlock|
handlers := OrderedCollection new.
newBlock := [ :node | aBlock value: node. self remove ].
handlers add: newBlock
]
{ #category : #stepping }
DiyaTimerNode >> step [
elapsedTime := elapsedTime + self delta.
elapsedTime >= timeout ifFalse:[^ self].
handlers do:[:e| e value: self ].
elapsedTime := 0
]
{ #category : #accessing }
DiyaTimerNode >> timeout [
^ timeout
]
{ #category : #accessing }
DiyaTimerNode >> timeout: anObject [
timeout := anObject
]

View File

@ -0,0 +1,54 @@
Class {
#name : #DiyaUIThemesManager,
#superclass : #DiyaSingleton,
#instVars : [
'themes',
'currentThemeName'
],
#category : #'Diya-UIThemes'
}
{ #category : #adding }
DiyaUIThemesManager >> addTheme:name stylesheet:sheet [
themes at:name put: sheet
]
{ #category : #accessing }
DiyaUIThemesManager >> currentTheme [
^ themes at: self currentThemeName ifAbsent: [
DiyaCoreAPIError signal: 'Undefined theme named', self currentThemeName
]
]
{ #category : #accessing }
DiyaUIThemesManager >> currentThemeName [
^ currentThemeName
]
{ #category : #accessing }
DiyaUIThemesManager >> currentThemeName: anObject [
currentThemeName := anObject
]
{ #category : #initialization }
DiyaUIThemesManager >> defaultTheme [
^ themes at: #default
]
{ #category : #initialization }
DiyaUIThemesManager >> defineDefaultTheme [
self addTheme: #default stylesheet: DiyaDefaultTheme new.
]
{ #category : #initialization }
DiyaUIThemesManager >> initialize [
super initialize.
themes := Dictionary new.
self defineDefaultTheme.
self currentThemeName: #default.
]
{ #category : #accessing }
DiyaUIThemesManager >> themes [
^ themes
]

View File

@ -1,5 +1,29 @@
Class {
#name : #DiyaWidget,
#superclass : #Diya2DNode,
#instVars : [
'extent'
],
#category : #'Diya-Widgets'
}
{ #category : #'instance creation' }
DiyaWidget class >> fromStyle: aStyle [
^self new style: aStyle; yourself
]
{ #category : #geometry }
DiyaWidget >> extent [
^extent
]
{ #category : #geometry }
DiyaWidget >> extent: size [
extent := size.
self setDirty.
]
{ #category : #initialization }
DiyaWidget >> initialize [
super initialize.
]

View File

@ -51,17 +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',
@ -60,6 +62,7 @@ Class {
'GL_SRC_ALPHA',
'GL_STATIC_DRAW',
'GL_STENCIL_BUFFER_BIT',
'GL_STREAM_DRAW',
'GL_TESS_CONTROL_SHADER',
'GL_TESS_EVALUATION_SHADER',
'GL_TEXTURE_2D',
@ -106,6 +109,7 @@ OpenGLConstants class >> initCommonConstants [
GL_UNIFORM_BUFFER := 16r8A11.
GL_STATIC_DRAW := 16r88E4.
GL_DYNAMIC_DRAW := 16r88E8.
GL_STREAM_DRAW := 16r88E0.
GL_FALSE := 0.
GL_TRUE := 1.
GL_ARRAY_BUFFER_BINDING := 16r8894.
@ -115,6 +119,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

@ -6,7 +6,13 @@ Class {
'cellw',
'cellh',
'spacing',
'fontSize'
'fontSize',
'colp',
'rowp',
'face',
'maxbearing',
'maxrows',
'meanww'
],
#pools : [
'OpenGLConstants',
@ -26,7 +32,6 @@ OpenGLFontTex >> blitPixel8: bitmap at: offset size: size [
0 to: size y - 1 do: [ :i|
LibC memCopy: (bitmap getHandle + (i* (size x))) to:(data getHandle + ((i + offset y) * width + (offset x) )) size: size x
].
bitmap free.
]
{ #category : #accessing }
@ -44,39 +49,6 @@ OpenGLFontTex >> charmap [
^ charmap
]
{ #category : #'instance creation' }
OpenGLFontTex >> createBitmapFontFrom: glyphs maxBearing: maxbearing [
|bmp metric offset nrows index element|
data ifNotNil: [data free ].
charmap := Dictionary new.
nrows := glyphs size >> 5.
(glyphs size % 32) = 0 ifFalse:[nrows := nrows + 1].
data := FFIExternalArray externalNewType: GLubyte size:cellw * cellh * (nrows << 5).
LibC memset: data getHandle value: 0 size: data size.
data autoRelease.
index := 1.
offset := 0@0.
width := cellw * 32.
height := cellh * nrows.
0 to: nrows - 1 do: [ :row|
0 to: 31 do: [ :col| |glyph|
element := glyphs at: index.
metric := element at: 3.
bmp := element at:2.
offset := (col * cellw) @ (row*cellh).
glyph := (DiyaFontGlyph origin: offset extent: ((metric first x asInteger) @ cellh)).
glyph
bearing: (metric at: 2) asFloatPoint;
advance: (metric at: 3) asFloatPoint;
texcoord: (Rectangle origin: (glyph origin/ (self extent) ) asFloatPoint corner: ((glyph corner) / (self extent)) asFloatPoint ).
charmap at: element first put:glyph.
self blitPixel8: bmp at: (offset x) @ ((offset y) + maxbearing - (metric last) ) size: metric first.
index := index + 1.
index > glyphs size ifTrue:[^self].
]
].
]
{ #category : #accessing }
OpenGLFontTex >> drop [
OpenGL
@ -91,50 +63,72 @@ OpenGLFontTex >> fontSize [
]
{ #category : #'instance creation' }
OpenGLFontTex >> fromFace: face ofSize: size [
|minhang maxbearing rec glyphs iptr charcode w|
OpenGLFontTex >> fromFace: aFace ofSize: size [
|minhang rec iptr charcode w numw|
fontSize := size.
face setPixelWidth:0 height: size.
glyphs := OrderedCollection new.
cellw := 0.
cellh := 0.
minhang := 0.
maxbearing := 0.
face := aFace.
charmap := Dictionary new.
face setPixelWidth:0 height: self fontSize.
cellw := cellh := minhang := maxbearing := 0.
iptr := FFIExternalArray externalNewType: GLuint size:1.
iptr at:1 put: 0.
rec := (FTFaceRec fromHandle: face getHandle).
charcode := face getFirstChar: iptr getHandle.
meanww := 0.
numw := 0.
[ (iptr at: 1) = 0 ] whileFalse: [
|bmp bmpsize metric|
face loadCharacter: charcode flags: (1 << 2).
w := ((rec glyph metrics width) >> 6).
(w > (size << 1)) ifFalse:[
metric := {
(((rec glyph metrics width) >> 6)@ ((rec glyph metrics height) >> 6)).
(face glyph hBearing).
(face glyph advance).
((rec glyph metrics horiBearingY) >> 6)
}.
maxbearing := maxbearing max: ((rec glyph metrics horiBearingY) >> 6).
cellw := cellw max: w.
minhang := minhang min: ((( rec glyph metrics horiBearingY) - (rec glyph metrics height)) >> 6).
"copy buffer"
bmpsize := (rec glyph bitmap width)*(rec glyph bitmap rows).
bmp := FFIExternalArray externalNewType: GLubyte size:bmpsize.
LibC memCopy: rec glyph bitmap buffer to: bmp getHandle size: bmpsize.
glyphs add: {charcode. bmp. metric}.
meanww := meanww + w.
numw := numw + 1.
].
charcode := face getNextChar: charcode iptr: iptr getHandle.
].
cellh := maxbearing - minhang.
spacing := (size >> 2) asInteger.
self createBitmapFontFrom: glyphs maxBearing: maxbearing.
spacing := (cellw >> 2) asInteger.
meanww := meanww / numw.
maxrows := 8.
data := FFIExternalArray externalNewType: GLubyte size:cellw * cellh * (maxrows << 5).
LibC memset: data getHandle value: 0 size: data size.
width := cellw << 5.
height := cellh.
data autoRelease.
iptr free.
]
{ #category : #accessing }
OpenGLFontTex >> genGlyph:c [
|rec offset glyph gsize|
face setPixelWidth:0 height: self fontSize.
face loadCharacter: c flags: (1 << 2).
rec := (FTFaceRec fromHandle: face getHandle).
gsize := ((rec glyph metrics width) >> 6)@((rec glyph metrics height) >> 6).
offset := (colp * cellw) @ (rowp*cellh).
glyph := (DiyaFontGlyph origin: offset extent: ((gsize x) @ cellh)).
glyph
bearing: face glyph hBearing asFloatPoint;
advance: face glyph advance;
tex: self.
self blitPixel8: rec glyph bitmap buffer at: (offset x) @ ((offset y) + maxbearing - ((rec glyph metrics horiBearingY) >> 6) ) size: gsize.
colp := (colp + 1) % 32.
colp = 0 ifTrue:[
rowp := rowp + 1.
height := height + cellh.
rowp >= maxrows ifTrue:[
self reallocateBuffer.
].
].
^glyph
]
{ #category : #accessing }
OpenGLFontTex >> getGlyph: c [
^(self charmap at: c ifAbsent:[^nil])
^(self charmap at: c ifAbsentPut:[self genGlyph:c])
]
{ #category : #initialization }
@ -148,6 +142,8 @@ OpenGLFontTex >> initialize [
internalFormat := GL_ALPHA.
type := GL_UNSIGNED_BYTE.
target := GL_TEXTURE_2D.
colp := 0.
rowp := 0.
]
{ #category : #accessing }
@ -155,6 +151,24 @@ OpenGLFontTex >> linespace [
^ cellh
]
{ #category : #accessing }
OpenGLFontTex >> meanww [
^ meanww
]
{ #category : #accessing }
OpenGLFontTex >> reallocateBuffer [
|newbuffer|
maxrows := maxrows + 4.
newbuffer := FFIExternalArray externalNewType: GLubyte size:cellw * cellh * (maxrows << 5).
LibC memset: newbuffer getHandle value: 0 size: newbuffer size.
LibC memCopy: data getHandle to: newbuffer getHandle size: data size.
newbuffer autoRelease.
data free.
data := newbuffer
]
{ #category : #accessing }
OpenGLFontTex >> setup [
OpenGL

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))
@ -136,7 +131,7 @@ OpenGLSL >> checkStatus:status of: id [
] ifFalse: [
OpenGLSL getShaderInfoLogOf: id maxLength: (infoLength at: 1) lengthPtr: nil buffer: buffer
].
^self error: buffer asString
^DiyaCoreAPIError signal: buffer asString
].
^self
@ -222,7 +217,7 @@ OpenGLSL >> locateUniforms [
OpenGLSL >> setUniform: uname value: values [
|uniform|
uniform := uniforms at: uname asSymbol ifAbsent:[
^self error: 'Uniform ', uname, ' is not defined in this program'].
^DiyaCoreAPIError signal: 'Uniform ', uname, ' is not defined in this program'].
uniform value: values
]

View File

@ -29,6 +29,11 @@ OpenGLTexImage2D >> border: anObject [
border := anObject
]
{ #category : #accessing }
OpenGLTexImage2D >> bytesSize [
^(width * height) << 2
]
{ #category : #accessing }
OpenGLTexImage2D >> data [
^ data
@ -59,7 +64,7 @@ OpenGLTexImage2D >> drop [
{ #category : #accessing }
OpenGLTexImage2D >> extent [
^ width @ height
^ self width @ self height
]
{ #category : #accessing }

View File

@ -26,7 +26,7 @@ OpenGLVertexBuffer class >> deleteBuffersSize:n buffers: buffers [
^self ffiCall: #(void glDeleteBuffers( GLsizei n,const GLuint * buffers))
]
{ #category : #'as yet unclassified' }
{ #category : #'library path' }
OpenGLVertexBuffer class >> ffiLibraryName [
^ OpenGL ffiLibraryName
]
@ -78,7 +78,8 @@ OpenGLVertexBuffer >> initialize [
vertexBufferID := FFIExternalArray externalNewType: GLint size:1.
vertexBufferID at:1 put: -1.
vertexBufferID autoRelease.
OpenGLVertexBuffer genVertexBuffersSize: 1 buffers: vertexBufferID getHandle
OpenGLVertexBuffer genVertexBuffersSize: 1 buffers: vertexBufferID getHandle.
]
{ #category : #'as yet unclassified' }

View File

@ -27,10 +27,10 @@ OrthoProjectionMatrix >> bottom [
{ #category : #initialization }
OrthoProjectionMatrix >> calculate [
self at:1 at:1 put: (2.0 /(self right - self left)).
self at:2 at:2 put: (2.0 / (self top - self bottom)).
self at:2 at:2 put: (2.0 / (self bottom - self top)).
self at:3 at:3 put: (2.0 / (self far - self near)) negated.
self at:4 at:1 put: ((self right + self left)/ (self right - self left)) negated.
self at:4 at:2 put: ((self top + self bottom) / (self top - self bottom)) negated.
self at:4 at:2 put: ((self top + self bottom) / (self bottom - self top)) negated.
self at:4 at:3 put: ((self far + self near)/(self far - self near)) negated.
]

View File

@ -1,16 +1,11 @@
Extension { #name : #Point }
{ #category : #'*Diya' }
Point >> asGLCoord [
|res|
res := DiyaRendererContext uniqueInstance resolution.
^(self / ( res / 2.0)) + (-1.0@ -1.0).
Point >> asArray3F [
^ self asArray3F: 1.0
]
{ #category : #'*Diya' }
Point >> glNormalise [
|res p|
res := DiyaRendererContext uniqueInstance resolution.
p := self / (res/ 2).
^ (p x asFloat) @ (p y asFloat)
Point >> asArray3F: z [
^ { self x. self y. z }
]

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

@ -0,0 +1,6 @@
Extension { #name : #SDL2MappedEvent }
{ #category : #'*Diya' }
SDL2MappedEvent >> triggableOn: aNode [
^aNode isRoot
]

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

@ -0,0 +1,11 @@
Extension { #name : #'SDL_MouseButtonEvent' }
{ #category : #'*Diya' }
SDL_MouseButtonEvent >> triggableOn: aNode [
^ aNode inner: self worldPosition
]
{ #category : #'*Diya' }
SDL_MouseButtonEvent >> worldPosition [
^ (self x) @ (self y )
]

View File

@ -0,0 +1,11 @@
Extension { #name : #'SDL_MouseMotionEvent' }
{ #category : #'*Diya' }
SDL_MouseMotionEvent >> triggableOn: arg1 [
^ arg1 inner: self worldPosition
]
{ #category : #'*Diya' }
SDL_MouseMotionEvent >> worldPosition [
^ (self x) @ (self y )
]

View File

@ -0,0 +1,13 @@
Extension { #name : #'SDL_TouchFingerEvent' }
{ #category : #'*Diya' }
SDL_TouchFingerEvent >> triggableOn: aNode [
^ aNode inner: self worldPosition
]
{ #category : #'*Diya' }
SDL_TouchFingerEvent >> worldPosition [
|resolution|
resolution := DiyaRendererContext uniqueInstance 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))

View File

@ -0,0 +1,6 @@
Extension { #name : #SmalltalkImage }
{ #category : #'*Diya' }
SmalltalkImage >> getenv: key [
^ self ffiCall: #(char *getenv(const char *key)) module: LibC
]

27
Jenkinsfile vendored Normal file
View File

@ -0,0 +1,27 @@
pipeline{
agent { node{ label'master' }}
options {
// Limit build history with buildDiscarder option:
// daysToKeepStr: history is only kept up to this many days.
// numToKeepStr: only this many build logs are kept.
// artifactDaysToKeepStr: artifacts are only kept up to this many days.
// artifactNumToKeepStr: only this many builds have their artifacts kept.
buildDiscarder(logRotator(numToKeepStr: "1"))
// Enable timestamps in build log console
timestamps()
// Maximum time to run the whole pipeline before canceling it
timeout(time: 1, unit: 'HOURS')
// Use Jenkins ANSI Color Plugin for log console
ansiColor('xterm')
// Limit build concurrency to 1 per branch
disableConcurrentBuilds()
}
stages
{
stage('Build image from SDK') {
steps {
build job: 'Diya-image', propagate: true, wait: true
}
}
}
}