From 6808a3aa0b2c52937e78d090a96d670a0fcee3c2 Mon Sep 17 00:00:00 2001 From: Dany LE Date: Wed, 2 Mar 2022 20:11:01 +0100 Subject: [PATCH] Add basic graph nodes and support basic transformation --- Diya/Array.extension.st | 6 +++ Diya/Diya2DNode.class.st | 47 +++++++----------- Diya/DiyaBoot.class.st | 37 +++++--------- Diya/DiyaComposableNode.class.st | 37 ++++++++++++++ Diya/DiyaFontManager.class.st | 6 +-- Diya/DiyaNode.class.st | 25 ++++++++-- Diya/DiyaRectangle.class.st | 82 +++++++++++++++++++++++++++++++ Diya/DiyaRenderer.class.st | 23 +++++---- Diya/DiyaRendererContext.class.st | 34 ++++++++++++- Diya/DiyaRootNode.class.st | 40 +++++++-------- Diya/GLSimpleShader.class.st | 3 ++ Diya/OpenGLConstants.class.st | 2 + Diya/OpenGLSLUniform.class.st | 5 ++ Diya/Point.extension.st | 16 ++++++ Diya/SimpleDiyaRenderer.class.st | 69 -------------------------- Diya/UniformMatrix4fv.class.st | 18 +++++++ 16 files changed, 285 insertions(+), 165 deletions(-) create mode 100644 Diya/Array.extension.st create mode 100644 Diya/DiyaComposableNode.class.st create mode 100644 Diya/DiyaRectangle.class.st create mode 100644 Diya/Point.extension.st delete mode 100644 Diya/SimpleDiyaRenderer.class.st create mode 100644 Diya/UniformMatrix4fv.class.st diff --git a/Diya/Array.extension.st b/Diya/Array.extension.st new file mode 100644 index 0000000..5354d3f --- /dev/null +++ b/Diya/Array.extension.st @@ -0,0 +1,6 @@ +Extension { #name : #Array } + +{ #category : #'*Diya' } +Array >> asPoint [ + ^ (self at: 1 ifAbsent:[0]) @ (self at: 2 ifAbsent:[0]) +] diff --git a/Diya/Diya2DNode.class.st b/Diya/Diya2DNode.class.st index c0e6024..c205f08 100644 --- a/Diya/Diya2DNode.class.st +++ b/Diya/Diya2DNode.class.st @@ -4,47 +4,36 @@ Class { #category : #'Diya-Graphics' } -{ #category : #accessing } -Diya2DNode >> drawOn: context [ - ^self subclassResponsibility -] - { #category : #initialization } Diya2DNode >> initialize [ super initialize. translation := 0@0. - scale := 0@0. + scale := 1.0@1.0. rotation := 0.0. tf := Array2D identity: 3. ] -{ #category : #accessing } -Diya2DNode >> renderOn: context [ - self updateTF. - self drawOn: context. -] - { #category : #accessing } Diya2DNode >> updateTF [ tf := Array2D identity:3. "translation" - tf := tf +* { - 1. 0. translation x. - 0. 1. translation y. - 0. 0. 1 - }. - "scale" - tf := tf +* { - scale x. 0. 0. - 0. scale y. 0. - 0. 0. 1. - }. + 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 + }). "rotation" - tf := tf +* { - rotation cos. 0-(rotation sin). 0. - rotation sin. rotation cos. 0. - 0. 0. 1 - }. - self parent = DiyaRootNode uniqueInstance ifTrue: [ ^tf ]. + 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 ifTrue: [ ^tf ]. tf := self parent tf +* tf ] diff --git a/Diya/DiyaBoot.class.st b/Diya/DiyaBoot.class.st index 0ab735f..03531c8 100644 --- a/Diya/DiyaBoot.class.st +++ b/Diya/DiyaBoot.class.st @@ -65,6 +65,7 @@ DiyaBoot >> init [ ifFalse: [ ^ self error: SDL2 getErrorMessage ]. display := SDL_DisplayMode externalNew autoRelease. SDL2 SDLGetCurrentDisplayMode: display from:0. + DiyaRendererContext reset. ] { #category : #events } @@ -98,30 +99,21 @@ DiyaBoot >> randomColorChannel [ { #category : #events } DiyaBoot >> render [ - |event| + |event root rec| event := SDL_Event new. + root := DiyaRootNode new. + DiyaRenderer uniqueInstance root: root. + rec := root addNode: (DiyaRectangle size: 120@160 shader: GLSimpleShader uniqueInstance) at: 120 @ 160. + rec rotation: (Float pi / -8.0). + rec scale: 1.5@1.5. + OpenGL viewportX: 0 Y:0 W: display w H: display h. [ running ] whileTrue: [ - [ (SDL2 pollEvent: event) > 0 ] whileTrue: [ + (SDL2 pollEvent: event) > 0 ifTrue: [ self processEvent: event ]. - self step. + DiyaRenderer uniqueInstance render. SDL2 glSwapWindow: window. - SDL2 delay: 50. - ]. -] - -{ #category : #events } -DiyaBoot >> render:sr [ - |event| - event := SDL_Event new. - [ running ] whileTrue: [ - [ (SDL2 pollEvent: event) > 0 ] whileTrue: [ - self processEvent: event - ]. - OpenGL viewportX: 0 Y:0 W: display w H: display h . - sr render. - SDL2 glSwapWindow: window. - SDL2 delay: 50. + "SDL2 delay: 50. " ]. ] @@ -200,21 +192,18 @@ DiyaBoot >> showSystemInfo [ { #category : #events } DiyaBoot >> startx [ - |sr| display ifNil: [ ^self error: 'Please run #init before this method' ]. self createWindow. self createGLContext. self createRenderer. self showSystemInfo. DiyaRendererContext uniqueInstance display: display. - sr := SimpleDiyaRenderer new. - sr setup. - self render:sr. - sr destroy. + self render. context delete. renderer destroy. window destroy. DiyaFontManager reset. + DiyaRendererContext reset. SDL2 quit. ] diff --git a/Diya/DiyaComposableNode.class.st b/Diya/DiyaComposableNode.class.st new file mode 100644 index 0000000..010640c --- /dev/null +++ b/Diya/DiyaComposableNode.class.st @@ -0,0 +1,37 @@ +Class { + #name : #DiyaComposableNode, + #superclass : #DiyaNode, + #instVars : [ + 'children' + ], + #category : #'Diya-Graphics' +} + +{ #category : #accessing } +DiyaComposableNode >> addNode: node [ + ^self addNode: node at: 0@0 +] + +{ #category : #accessing } +DiyaComposableNode >> addNode: node at: pos [ + node parent: self. + node position: pos. + children add: node. + ^ node +] + +{ #category : #accessing } +DiyaComposableNode >> children [ + ^ children +] + +{ #category : #initialization } +DiyaComposableNode >> initialize [ + super initialize. + children := OrderedCollection new. +] + +{ #category : #accessing } +DiyaComposableNode >> render [ + children do: [:c | c render ]. +] diff --git a/Diya/DiyaFontManager.class.st b/Diya/DiyaFontManager.class.st index b5349cb..12dd829 100644 --- a/Diya/DiyaFontManager.class.st +++ b/Diya/DiyaFontManager.class.st @@ -9,14 +9,10 @@ Class { { #category : #'instance creation' } DiyaFontManager class >> cleanUpInstance: singleton [ + singleton ifNil:[^self]. singleton reset. ] -{ #category : #'class initialization' } -DiyaFontManager class >> initialize [ - self uniqueInstance reset. -] - { #category : #'as yet unclassified' } DiyaFontManager class >> searchPaths [ ^ { diff --git a/Diya/DiyaNode.class.st b/Diya/DiyaNode.class.st index 0751f12..5a18229 100644 --- a/Diya/DiyaNode.class.st +++ b/Diya/DiyaNode.class.st @@ -7,7 +7,8 @@ Class { 'scale', 'rotation', 'tf', - 'shader' + 'shader', + 'context' ], #pools : [ 'OpenGLConstants', @@ -26,6 +27,12 @@ DiyaNode >> initialize [ super initialize. parent := nil. shader := DiyaDefaultShader uniqueInstance. + context := DiyaRendererContext uniqueInstance. +] + +{ #category : #testing } +DiyaNode >> isRoot [ + ^false ] { #category : #accessing } @@ -33,6 +40,11 @@ DiyaNode >> parent [ ^ parent ] +{ #category : #accessing } +DiyaNode >> parent: anObject [ + parent := anObject +] + { #category : #accessing } DiyaNode >> position [ ^ translation @@ -40,11 +52,12 @@ DiyaNode >> position [ { #category : #accessing } DiyaNode >> position: anObject [ - translation := anObject + translation := anObject. + self updateTF. ] { #category : #accessing } -DiyaNode >> renderOn: context [ +DiyaNode >> render [ ^self subclassResponsibility ] @@ -55,7 +68,8 @@ DiyaNode >> rotation [ { #category : #accessing } DiyaNode >> rotation: anObject [ - rotation := anObject + rotation := anObject. + self updateTF. ] { #category : #accessing } @@ -65,7 +79,8 @@ DiyaNode >> scale [ { #category : #accessing } DiyaNode >> scale: anObject [ - scale := anObject + scale := anObject. + self updateTF. ] { #category : #accessing } diff --git a/Diya/DiyaRectangle.class.st b/Diya/DiyaRectangle.class.st new file mode 100644 index 0000000..c66b189 --- /dev/null +++ b/Diya/DiyaRectangle.class.st @@ -0,0 +1,82 @@ +Class { + #name : #DiyaRectangle, + #superclass : #Diya2DNode, + #instVars : [ + 'size' + ], + #category : #'Diya-Graphics' +} + +{ #category : #'as yet unclassified' } +DiyaRectangle class >> size: s [ + ^(self new) size:s; yourself +] + +{ #category : #'as yet unclassified' } +DiyaRectangle class >> size: size shader:s [ + ^(self with:s) size: size; yourself +] + +{ #category : #accessing } +DiyaRectangle >> initialize [ + super initialize. + self size:10@10. +] + +{ #category : #accessing } +DiyaRectangle >> render [ + |buffer| + buffer := FFIExternalArray externalNewType: GLfloat size: 12. + self transformDo:[:i :e| + buffer at:i put:e + ]. + context vbo bind: GL_ARRAY_BUFFER. + context vbo data: GL_ARRAY_BUFFER data:buffer usage: GL_STATIC_DRAW. + shader use. + shader setUniform: #u_time value: DiyaClock uniqueInstance elapsedTime asFloat. + shader setUniform: #u_resolution value: { context resolution x. context resolution y }. + context mouse ifNotNil: [ + "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 vao enableAttribute: 0. + context vbo bind: GL_ARRAY_BUFFER. + OpenGLVertexArray vertexAttributePointerIndex: 0 size:3 type: GL_FLOAT normalized: GL_FALSE stride: 0 pointer: nil . + OpenGL drawArrays: GL_QUADS first:0 count: 4. + context vao disableAttribute: 0. + buffer free. +] + +{ #category : #accessing } +DiyaRectangle >> size [ + ^ size +] + +{ #category : #accessing } +DiyaRectangle >> size: anObject [ + size := anObject. +] + +{ #category : #accessing } +DiyaRectangle >> transform [ + |origin topleft topright bottomright| + origin := (self tf +* #(0.0 0.0 1.0)) asPoint asGLCoord. + topleft := (self tf +* { 0.0. size y.1.0 }) asPoint asGLCoord. + topright := (self tf +* { size x. size y.1.0 }) asPoint asGLCoord. + bottomright := (self tf +* { size x. 0.0. 1.0 }) asPoint asGLCoord. + ^ + { + origin x. origin y. 0.0. + topleft x. topleft y. 0.0. + topright x. topright y. 0.0. + bottomright x. bottomright y. 0.0. + } +] + +{ #category : #accessing } +DiyaRectangle >> transformDo: block [ + |i| + i := 1. + self transform do:[:e| block value:i value:e. i := i+1]. +] diff --git a/Diya/DiyaRenderer.class.st b/Diya/DiyaRenderer.class.st index bd5b8fe..140ee00 100644 --- a/Diya/DiyaRenderer.class.st +++ b/Diya/DiyaRenderer.class.st @@ -1,8 +1,8 @@ Class { #name : #DiyaRenderer, - #superclass : #DiyaBaseObject, + #superclass : #DiyaSingleton, #instVars : [ - 'context' + 'root' ], #pools : [ 'OpenGLConstants', @@ -16,23 +16,22 @@ DiyaRenderer class >> fromContext: ctx [ ^self new context: ctx; yourself ] -{ #category : #deleting } -DiyaRenderer >> destroy [ - ^ self subclassResponsibility -] - { #category : #initialization } DiyaRenderer >> initialize [ super initialize. - context := DiyaRendererContext uniqueInstance ] { #category : #deleting } DiyaRenderer >> render [ - ^ self subclassResponsibility + root render. ] -{ #category : #deleting } -DiyaRenderer >> setup [ - ^ self subclassResponsibility +{ #category : #accessing } +DiyaRenderer >> root [ + ^ root +] + +{ #category : #accessing } +DiyaRenderer >> root: anObject [ + root := anObject ] diff --git a/Diya/DiyaRendererContext.class.st b/Diya/DiyaRendererContext.class.st index 5b0ac21..841f32e 100644 --- a/Diya/DiyaRendererContext.class.st +++ b/Diya/DiyaRendererContext.class.st @@ -3,7 +3,9 @@ Class { #superclass : #DiyaSingleton, #instVars : [ 'mouse', - 'display' + 'display', + 'vbo', + 'vao' ], #pools : [ 'OpenGLConstants', @@ -12,6 +14,17 @@ Class { #category : #'Diya-Graphics' } +{ #category : #'instance creation' } +DiyaRendererContext class >> cleanUpInstance: singleton [ + singleton destroy +] + +{ #category : #accessing } +DiyaRendererContext >> destroy [ + vao delete. + vbo delete. +] + { #category : #accessing } DiyaRendererContext >> display [ ^ display @@ -22,6 +35,15 @@ DiyaRendererContext >> display: anObject [ display := anObject ] +{ #category : #accessing } +DiyaRendererContext >> initialize [ + super initialize. + vbo := OpenGLVertexBuffer new. + vao := OpenGLVertexArray new. + vao bind. + vbo bind: GL_ARRAY_BUFFER. +] + { #category : #accessing } DiyaRendererContext >> mouse [ ^ mouse @@ -36,3 +58,13 @@ DiyaRendererContext >> mouse: anObject [ DiyaRendererContext >> resolution [ ^ (display w) @ (display h) ] + +{ #category : #accessing } +DiyaRendererContext >> vao [ + ^ vao +] + +{ #category : #accessing } +DiyaRendererContext >> vbo [ + ^ vbo +] diff --git a/Diya/DiyaRootNode.class.st b/Diya/DiyaRootNode.class.st index aaad2f1..570a418 100644 --- a/Diya/DiyaRootNode.class.st +++ b/Diya/DiyaRootNode.class.st @@ -1,30 +1,30 @@ Class { #name : #DiyaRootNode, - #superclass : #DiyaNode, - #classVars : [ - 'singleton' - ], + #superclass : #DiyaComposableNode, #category : #'Diya-Graphics' } -{ #category : #'instance creation' } -DiyaRootNode class >> new [ - self error: 'Please use uniqueInstance' -] - -{ #category : #'instance creation' } -DiyaRootNode class >> reset [ - singleton := nil -] - -{ #category : #'instance creation' } -DiyaRootNode class >> uniqueInstance [ - singleton ifNil: [ singleton := super new]. - ^singleton -] - { #category : #initialization } DiyaRootNode >> initialize [ super initialize. parent := self. ] + +{ #category : #testing } +DiyaRootNode >> isRoot [ + ^ true +] + +{ #category : #accessing } +DiyaRootNode >> render [ + OpenGL clearColorR: 1.0 G: 0 B: 1.0 A:0. + OpenGL clear: GL_COLOR_BUFFER_BIT. + "render all child node" + children do: [:c | c render ]. + +] + +{ #category : #accessing } +DiyaRootNode >> updateTF [ + "donothing" +] diff --git a/Diya/GLSimpleShader.class.st b/Diya/GLSimpleShader.class.st index c712ed5..3477786 100644 --- a/Diya/GLSimpleShader.class.st +++ b/Diya/GLSimpleShader.class.st @@ -26,6 +26,9 @@ void main() { #category : #accessing } GLSimpleShader class >> vertextShader [ ^ ' +#ifdef GL_ES +precision mediump float; +#endif void main() { gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; diff --git a/Diya/OpenGLConstants.class.st b/Diya/OpenGLConstants.class.st index a259e26..c1405b8 100644 --- a/Diya/OpenGLConstants.class.st +++ b/Diya/OpenGLConstants.class.st @@ -17,6 +17,7 @@ Class { 'GL_DELETE_STATUS', 'GL_DEPTH_BUFFER_BIT', 'GL_DOUBLE', + 'GL_DYNAMIC_DRAW', 'GL_FALSE', 'GL_FIXED', 'GL_FLOAT', @@ -77,6 +78,7 @@ OpenGLConstants class >> initCommonConstants [ GL_TEXTURE_BUFFER := 16r8C2A. GL_UNIFORM_BUFFER := 16r8A11. GL_STATIC_DRAW := 16r88E4. + GL_DYNAMIC_DRAW := 16r88E8. GL_FALSE := 0. GL_TRUE := 1. GL_ARRAY_BUFFER_BINDING := 16r8894 diff --git a/Diya/OpenGLSLUniform.class.st b/Diya/OpenGLSLUniform.class.st index 148267b..93bd29f 100644 --- a/Diya/OpenGLSLUniform.class.st +++ b/Diya/OpenGLSLUniform.class.st @@ -68,6 +68,11 @@ OpenGLSLUniform class >> uniform4i: location value: v0 value: v1 value: v2 value ^self ffiCall: #(void glUniform4i(GLint location,GLint v0,GLint v1,GLint v2, GLint v3)) ] +{ #category : #'as yet unclassified' } +OpenGLSLUniform class >> uniformMatrix4fv: location count: count transpose: transpose value: value [ + ^self ffiCall: #(void glUniformMatrix4fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat *value)) +] + { #category : #accessing } OpenGLSLUniform >> location [ ^ location diff --git a/Diya/Point.extension.st b/Diya/Point.extension.st new file mode 100644 index 0000000..de29c42 --- /dev/null +++ b/Diya/Point.extension.st @@ -0,0 +1,16 @@ +Extension { #name : #Point } + +{ #category : #'*Diya' } +Point >> asGLCoord [ + |res| + res := DiyaRendererContext uniqueInstance resolution. + ^(self / ( res / 2.0)) + (-1.0@ -1.0). +] + +{ #category : #'*Diya' } +Point >> glNormalise [ + |res p| + res := DiyaRendererContext uniqueInstance resolution. + p := self / (res/ 2). + ^ (p x asFloat) @ (p y asFloat) +] diff --git a/Diya/SimpleDiyaRenderer.class.st b/Diya/SimpleDiyaRenderer.class.st deleted file mode 100644 index e6dbebf..0000000 --- a/Diya/SimpleDiyaRenderer.class.st +++ /dev/null @@ -1,69 +0,0 @@ -Class { - #name : #SimpleDiyaRenderer, - #superclass : #DiyaRenderer, - #instVars : [ - 'vertexBuffer', - 'arrayBuffer', - 'bufferData', - 'shader' - ], - #category : #'Diya-Graphics' -} - -{ #category : #deleting } -SimpleDiyaRenderer >> destroy [ - vertexBuffer delete. - arrayBuffer delete. - GLSimpleShader reset. -] - -{ #category : #initialization } -SimpleDiyaRenderer >> initialize [ - super initialize. - vertexBuffer := OpenGLVertexBuffer new. - arrayBuffer := OpenGLVertexArray new. - bufferData := FFIExternalArray externalNewType: GLfloat size: 12. - bufferData autoRelease. - shader := GLSimpleShader uniqueInstance. - -] - -{ #category : #deleting } -SimpleDiyaRenderer >> render [ - OpenGL clearColorR: 1.0 G: 0 B: 1.0 A:0. - OpenGL clear: GL_COLOR_BUFFER_BIT. - shader use. - shader setUniform: #u_time value: DiyaClock uniqueInstance elapsedTime asFloat. - shader setUniform: #u_resolution value: { context resolution x. context resolution y }. - context mouse ifNotNil: [ - "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 }. - ]. - - arrayBuffer enableAttribute: 0. - vertexBuffer bind: GL_ARRAY_BUFFER. - OpenGLVertexArray vertexAttributePointerIndex: 0 size:3 type: GL_FLOAT normalized: GL_FALSE stride: 0 pointer: nil . - OpenGL drawArrays: GL_QUADS first:0 count: 4. - arrayBuffer disableAttribute: 0. -] - -{ #category : #deleting } -SimpleDiyaRenderer >> setup [ -bufferData - at: 1 put: -1.0; - at: 2 put: -1.0; - at: 3 put: 0; - at: 4 put: 1.0; - at: 5 put: -1.0; - at: 6 put: 0; - at: 7 put: 1.0; - at: 8 put: 1.0; - at: 9 put: 0; - at: 10 put: -1.0; - at: 11 put: 1.0; - at: 12 put: 0. - arrayBuffer bind. - vertexBuffer bind: GL_ARRAY_BUFFER. - vertexBuffer data: GL_ARRAY_BUFFER data:bufferData usage: GL_STATIC_DRAW. -] diff --git a/Diya/UniformMatrix4fv.class.st b/Diya/UniformMatrix4fv.class.st new file mode 100644 index 0000000..819ea39 --- /dev/null +++ b/Diya/UniformMatrix4fv.class.st @@ -0,0 +1,18 @@ +Class { + #name : #UniformMatrix4fv, + #superclass : #OpenGLSLUniform, + #pools : [ + 'OpenGLConstants', + 'OpenGLTypes' + ], + #category : #'Diya-OpenGL' +} + +{ #category : #accessing } +UniformMatrix4fv >> setUniformValue [ + OpenGLSLUniform + uniformMatrix4fv: location + count: 1 + transpose: GL_FALSE + value: value getHandle +]