From e047a89801c906a134448d834adf66f25e7aa6c5 Mon Sep 17 00:00:00 2001 From: Dany LE Date: Tue, 15 Feb 2022 18:04:54 +0100 Subject: [PATCH] add uniform support to shader --- Diya/DiyaBoot.class.st | 29 +++----- Diya/DiyaClock.class.st | 18 +++++ Diya/DiyaRenderer.class.st | 14 ++++ Diya/DiyaRendererContext.class.st | 38 +++++++++++ Diya/DiyaSingleton.class.st | 37 ++++++++++ Diya/Duration.extension.st | 6 ++ Diya/GLSimpleShader.class.st | 9 ++- Diya/OpenGLSL.class.st | 84 ++++++++++++++++------- Diya/OpenGLSLUniform.class.st | 108 ++++++++++++++++++++++++++++++ Diya/SimpleDiyaRenderer.class.st | 10 ++- Diya/Uniform1F.class.st | 14 ++++ Diya/Uniform1i.class.st | 14 ++++ Diya/Uniform2F.class.st | 14 ++++ Diya/Uniform2i.class.st | 14 ++++ Diya/Uniform3F.class.st | 14 ++++ Diya/Uniform3i.class.st | 14 ++++ Diya/Uniform4F.class.st | 18 +++++ Diya/Uniform4i.class.st | 18 +++++ 18 files changed, 426 insertions(+), 47 deletions(-) create mode 100644 Diya/DiyaClock.class.st create mode 100644 Diya/DiyaRendererContext.class.st create mode 100644 Diya/DiyaSingleton.class.st create mode 100644 Diya/Duration.extension.st create mode 100644 Diya/OpenGLSLUniform.class.st create mode 100644 Diya/Uniform1F.class.st create mode 100644 Diya/Uniform1i.class.st create mode 100644 Diya/Uniform2F.class.st create mode 100644 Diya/Uniform2i.class.st create mode 100644 Diya/Uniform3F.class.st create mode 100644 Diya/Uniform3i.class.st create mode 100644 Diya/Uniform4F.class.st create mode 100644 Diya/Uniform4i.class.st diff --git a/Diya/DiyaBoot.class.st b/Diya/DiyaBoot.class.st index 359f2be..2973141 100644 --- a/Diya/DiyaBoot.class.st +++ b/Diya/DiyaBoot.class.st @@ -1,15 +1,13 @@ Class { #name : #DiyaBoot, - #superclass : #DiyaBaseObject, + #superclass : #DiyaSingleton, #instVars : [ 'running', 'window', 'renderer', 'context', - 'display' - ], - #classVars : [ - 'singleton' + 'display', + 'clock' ], #pools : [ 'OpenGLConstants', @@ -20,16 +18,6 @@ Class { #category : #'Diya-Runtime' } -{ #category : #'instance creation' } -DiyaBoot class >> new [ - self error: 'Use #uniqueInstance' -] - -{ #category : #'instance creation' } -DiyaBoot class >> reset [ - singleton := nil -] - { #category : #'instance creation' } DiyaBoot class >> startUp: status [ self startx. @@ -40,12 +28,6 @@ DiyaBoot class >> startx [ self uniqueInstance run ] -{ #category : #'instance creation' } -DiyaBoot class >> uniqueInstance [ - singleton ifNil: [ singleton := super new ]. - ^ singleton -] - { #category : #events } DiyaBoot >> createGLContext [ context := SDL2 glCreateContext: window. @@ -91,6 +73,7 @@ DiyaBoot >> initialize [ display := nil. window := nil. context := nil. + clock := DiyaClock uniqueInstance. ] { #category : #events } @@ -101,6 +84,7 @@ DiyaBoot >> processEvent: event [ 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]. ] { #category : #events } @@ -167,6 +151,8 @@ DiyaBoot >> run: screenSize app: application [ display h: screenSize y. self startx. self class reset. + DiyaClock reset. + DiyaRendererContext reset. Smalltalk garbageCollect. ] @@ -220,6 +206,7 @@ DiyaBoot >> startx [ self createGLContext. self createRenderer. self showSystemInfo. + DiyaRendererContext uniqueInstance display: display. sr := SimpleDiyaRenderer new. sr setup. self render:sr. diff --git a/Diya/DiyaClock.class.st b/Diya/DiyaClock.class.st new file mode 100644 index 0000000..86a2f03 --- /dev/null +++ b/Diya/DiyaClock.class.st @@ -0,0 +1,18 @@ +Class { + #name : #DiyaClock, + #superclass : #DiyaSingleton, + #instVars : [ + 'monotonic' + ], + #category : #'Diya-Runtime' +} + +{ #category : #initialization } +DiyaClock >> elapsedTime [ + ^(DateAndTime now) - monotonic +] + +{ #category : #initialization } +DiyaClock >> initialize [ + monotonic := DateAndTime now. +] diff --git a/Diya/DiyaRenderer.class.st b/Diya/DiyaRenderer.class.st index 1a25251..bd5b8fe 100644 --- a/Diya/DiyaRenderer.class.st +++ b/Diya/DiyaRenderer.class.st @@ -1,6 +1,9 @@ Class { #name : #DiyaRenderer, #superclass : #DiyaBaseObject, + #instVars : [ + 'context' + ], #pools : [ 'OpenGLConstants', 'OpenGLTypes' @@ -8,11 +11,22 @@ Class { #category : #'Diya-Graphics' } +{ #category : #'instance creation' } +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 diff --git a/Diya/DiyaRendererContext.class.st b/Diya/DiyaRendererContext.class.st new file mode 100644 index 0000000..5b0ac21 --- /dev/null +++ b/Diya/DiyaRendererContext.class.st @@ -0,0 +1,38 @@ +Class { + #name : #DiyaRendererContext, + #superclass : #DiyaSingleton, + #instVars : [ + 'mouse', + 'display' + ], + #pools : [ + 'OpenGLConstants', + 'OpenGLTypes' + ], + #category : #'Diya-Graphics' +} + +{ #category : #accessing } +DiyaRendererContext >> display [ + ^ display +] + +{ #category : #accessing } +DiyaRendererContext >> display: anObject [ + display := anObject +] + +{ #category : #accessing } +DiyaRendererContext >> mouse [ + ^ mouse +] + +{ #category : #accessing } +DiyaRendererContext >> mouse: anObject [ + mouse := anObject +] + +{ #category : #'as yet unclassified' } +DiyaRendererContext >> resolution [ + ^ (display w) @ (display h) +] diff --git a/Diya/DiyaSingleton.class.st b/Diya/DiyaSingleton.class.st new file mode 100644 index 0000000..7d87291 --- /dev/null +++ b/Diya/DiyaSingleton.class.st @@ -0,0 +1,37 @@ +Class { + #name : #DiyaSingleton, + #superclass : #DiyaBaseObject, + #classVars : [ + 'singletons' + ], + #category : #'Diya-Core' +} + +{ #category : #'instance creation' } +DiyaSingleton class >> cleanUpInstance: singleton [ + "do nothing for now" +] + +{ #category : #'class initialization' } +DiyaSingleton class >> initialize [ + singletons := Dictionary new. +] + +{ #category : #'instance creation' } +DiyaSingleton class >> new [ + self error: 'Use #uniqueInstance' +] + +{ #category : #'instance creation' } +DiyaSingleton class >> reset [ + |singleton| + singleton := singletons at: self class ifAbsent: [ ^ self ]. + self cleanUpInstance: singleton. + singletons removeKey: self class +] + +{ #category : #'instance creation' } +DiyaSingleton class >> uniqueInstance [ + singletons at: self class ifAbsentPut: super new. + ^ singletons at: self class +] diff --git a/Diya/Duration.extension.st b/Diya/Duration.extension.st new file mode 100644 index 0000000..3ed0e6b --- /dev/null +++ b/Diya/Duration.extension.st @@ -0,0 +1,6 @@ +Extension { #name : #Duration } + +{ #category : #'*Diya' } +Duration >> asFloat [ + ^ seconds asFloat + (nanos / 1e9) asFloat +] diff --git a/Diya/GLSimpleShader.class.st b/Diya/GLSimpleShader.class.st index cbf56aa..3d4e2e0 100644 --- a/Diya/GLSimpleShader.class.st +++ b/Diya/GLSimpleShader.class.st @@ -7,9 +7,16 @@ Class { { #category : #accessing } GLSimpleShader class >> fragmentShader [ ^ ' +#ifdef GL_ES +precision mediump float; +#endif +uniform vec2 u_resolution; +uniform vec2 u_mouse; +uniform float u_time; void main() { - gl_FragColor = vec4(0.4,0.4,0.8,1.0); + vec2 mouse = vec2(u_mouse)/vec2(u_resolution); + gl_FragColor = vec4(mouse.x, mouse.y, abs(sin(u_time)), 1.0); } ' ] diff --git a/Diya/OpenGLSL.class.st b/Diya/OpenGLSL.class.st index 5636d64..ee47fe6 100644 --- a/Diya/OpenGLSL.class.st +++ b/Diya/OpenGLSL.class.st @@ -1,11 +1,9 @@ Class { #name : #OpenGLSL, - #superclass : #DiyaBaseObject, + #superclass : #DiyaSingleton, #instVars : [ - 'programID' - ], - #classVars : [ - 'singleton' + 'programID', + 'uniforms' ], #pools : [ 'OpenGLConstants', @@ -19,6 +17,11 @@ OpenGLSL class >> attachShader: shader to: program [ ^self ffiCall: #(void glAttachShader(GLuint program,GLuint shader)) ] +{ #category : #'instance creation' } +OpenGLSL class >> cleanUpInstance: singleton [ + singleton delete +] + { #category : #'as yet unclassified' } OpenGLSL class >> compileShader: shader [ ^ self ffiCall: #(void glCompileShader( GLuint shader)) @@ -74,33 +77,24 @@ OpenGLSL class >> getShaderiv:shader parameterName: pname params: ptr [ ^ self ffiCall: #(void glGetShaderiv(GLuint shader,GLenum pname,GLint *ptr)) ] +{ #category : #'as yet unclassified' } +OpenGLSL class >> getUniformLocation: uname ofProgram: program [ + ^self ffiCall:#(GLint glGetUniformLocation( GLuint program,const GLchar *uname)) +] + { #category : #'as yet unclassified' } OpenGLSL class >> linkProgram:program [ ^self ffiCall: #(void glLinkProgram(GLuint program)) ] -{ #category : #'instance creation' } -OpenGLSL class >> new [ - self error: 'Use #uniqueInstance' -] - -{ #category : #'instance creation' } -OpenGLSL class >> reset [ - singleton ifNotNil: [ - singleton delete. - ]. - singleton := nil -] - { #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)) ] -{ #category : #'instance creation' } -OpenGLSL class >> uniqueInstance [ - singleton ifNil: [ singleton := super new. singleton compile ]. - ^ singleton +{ #category : #'as yet unclassified' } +OpenGLSL class >> systemUniforms [ + ^#(u_time u_resolution u_mouse) ] { #category : #'as yet unclassified' } @@ -113,6 +107,11 @@ OpenGLSL class >> vertextShader [ ^ self subclassResponsibility ] +{ #category : #initialization } +OpenGLSL >> addUniform: uname of: utype [ + uniforms at:uname put: (utype fromName: uname). +] + { #category : #compiling } OpenGLSL >> checkStatus:status of: id [ |infoLength buffer result| @@ -151,7 +150,8 @@ OpenGLSL >> compile [ OpenGLSL detachShaderFrom: programID shader: vertexShaderID. OpenGLSL detachShaderFrom: programID shader: fragmentShaderID. OpenGLSL deleteShader: vertexShaderID. - OpenGLSL deleteShader: fragmentShaderID + OpenGLSL deleteShader: fragmentShaderID. + self locateUniforms ] { #category : #compiling } @@ -184,6 +184,44 @@ OpenGLSL >> getSourcePtr: string for: shaderId [ OpenGLSL setShaderSourceFor: shaderId count: 1 string: xarray getHandle length: nil. ] +{ #category : #'submorphs-add/remove' } +OpenGLSL >> getUniformLocation:uname [ + ^ self class getUniformLocation: uname asString ofProgram: programID +] + +{ #category : #initialization } +OpenGLSL >> initialize [ + super initialize. + uniforms := Dictionary new. + self addUniform: #u_time of: Uniform1F. + self addUniform: #u_resolution of: Uniform2F. + self addUniform: #u_mouse of: Uniform2F. + self setUpUniforms. + self compile +] + +{ #category : #compiling } +OpenGLSL >> locateUniforms [ + |loc| + uniforms valuesDo: [ :uniform| + loc := self getUniformLocation: uniform uname. + loc = -1 ifFalse:[uniform location: loc] + ] +] + +{ #category : #initialization } +OpenGLSL >> setUniform: uname value: values [ + |uniform| + uniform := uniforms at: uname asSymbol ifAbsent:[ + ^self error: 'Uniform', uname, 'is not defined in this program']. + uniform value: values +] + +{ #category : #initialization } +OpenGLSL >> setUpUniforms [ + "do nothing, custom uniform can be set up by subclass" +] + { #category : #'submorphs-add/remove' } OpenGLSL >> use [ ^OpenGLSL useProgram: programID diff --git a/Diya/OpenGLSLUniform.class.st b/Diya/OpenGLSLUniform.class.st new file mode 100644 index 0000000..148267b --- /dev/null +++ b/Diya/OpenGLSLUniform.class.st @@ -0,0 +1,108 @@ +Class { + #name : #OpenGLSLUniform, + #superclass : #DiyaBaseObject, + #instVars : [ + 'uname', + 'location', + 'value' + ], + #pools : [ + 'OpenGLConstants', + 'OpenGLTypes' + ], + #category : #'Diya-OpenGL' +} + +{ #category : #'as yet unclassified' } +OpenGLSLUniform class >> ffiLibraryName [ + ^ OpenGL ffiLibraryName +] + +{ #category : #'as yet unclassified' } +OpenGLSLUniform class >> fromName: uname [ + ^self new uname: uname; yourself +] + +{ #category : #'as yet unclassified' } +OpenGLSLUniform class >> fromName: uname at: location [ + ^self new uname: uname; location: location; yourself +] + +{ #category : #'as yet unclassified' } +OpenGLSLUniform class >> uniform1f: location value: v0 [ + ^self ffiCall: #(void glUniform1f(GLint location,GLfloat v0)) +] + +{ #category : #'as yet unclassified' } +OpenGLSLUniform class >> uniform1i: location value: v0 [ + ^self ffiCall: #(void glUniform1i(GLint location,GLint v0)) +] + +{ #category : #'as yet unclassified' } +OpenGLSLUniform class >> uniform2f: location value: v0 value: v1 [ + ^self ffiCall: #(void glUniform2f(GLint location,GLfloat v0,GLfloat v1)) +] + +{ #category : #'as yet unclassified' } +OpenGLSLUniform class >> uniform2i: location value: v0 value: v1 [ + ^self ffiCall: #(void glUniform2i(GLint location,GLint v0,GLint v1)) +] + +{ #category : #'as yet unclassified' } +OpenGLSLUniform class >> uniform3f: location value: v0 value: v1 value: v2 [ + ^self ffiCall: #(void glUniform3f(GLint location,GLfloat v0,GLfloat v1,GLfloat v2)) +] + +{ #category : #'as yet unclassified' } +OpenGLSLUniform class >> uniform3i: location value: v0 value: v1 value: v2 [ + ^self ffiCall: #(void glUniform3i(GLint location,GLint v0,GLint v1,GLint v2)) +] + +{ #category : #'as yet unclassified' } +OpenGLSLUniform class >> uniform4f: location value: v0 value: v1 value: v2 value: v3 [ + ^self ffiCall: #(void glUniform4f(GLint location,GLfloat v0,GLfloat v1,GLfloat v2, GLfloat v3)) +] + +{ #category : #'as yet unclassified' } +OpenGLSLUniform class >> uniform4i: location value: v0 value: v1 value: v2 value: v3 [ + ^self ffiCall: #(void glUniform4i(GLint location,GLint v0,GLint v1,GLint v2, GLint v3)) +] + +{ #category : #accessing } +OpenGLSLUniform >> location [ + ^ location +] + +{ #category : #accessing } +OpenGLSLUniform >> location: anObject [ + location := anObject +] + +{ #category : #accessing } +OpenGLSLUniform >> setUniformValue [ + ^ self subclassResponsibility + +] + +{ #category : #accessing } +OpenGLSLUniform >> uname [ + ^ uname +] + +{ #category : #accessing } +OpenGLSLUniform >> uname: anObject [ + uname := anObject +] + +{ #category : #accessing } +OpenGLSLUniform >> value [ + ^ value +] + +{ #category : #accessing } +OpenGLSLUniform >> value: values [ + location = -1 ifTrue: [ ^self ]. + value := values. + self setUniformValue. + +] diff --git a/Diya/SimpleDiyaRenderer.class.st b/Diya/SimpleDiyaRenderer.class.st index 552817d..89bf219 100644 --- a/Diya/SimpleDiyaRenderer.class.st +++ b/Diya/SimpleDiyaRenderer.class.st @@ -14,12 +14,12 @@ Class { SimpleDiyaRenderer >> destroy [ vertexBuffer delete. arrayBuffer delete. - shader delete. GLSimpleShader reset. ] { #category : #initialization } -SimpleDiyaRenderer >> initialize [ +SimpleDiyaRenderer >> initialize [ + super initialize. vertexBuffer := OpenGLVertexBuffer new. arrayBuffer := OpenGLVertexArray new. bufferData := FFIExternalArray externalNewType: GLfloat size: 9. @@ -33,6 +33,12 @@ 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: [ + shader setUniform: #u_mouse value: { context mouse x. 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 . diff --git a/Diya/Uniform1F.class.st b/Diya/Uniform1F.class.st new file mode 100644 index 0000000..263cf04 --- /dev/null +++ b/Diya/Uniform1F.class.st @@ -0,0 +1,14 @@ +Class { + #name : #Uniform1F, + #superclass : #OpenGLSLUniform, + #pools : [ + 'OpenGLConstants', + 'OpenGLTypes' + ], + #category : #'Diya-OpenGL' +} + +{ #category : #accessing } +Uniform1F >> setUniformValue [ + OpenGLSLUniform uniform1f: location value: value +] diff --git a/Diya/Uniform1i.class.st b/Diya/Uniform1i.class.st new file mode 100644 index 0000000..adf6395 --- /dev/null +++ b/Diya/Uniform1i.class.st @@ -0,0 +1,14 @@ +Class { + #name : #Uniform1i, + #superclass : #OpenGLSLUniform, + #pools : [ + 'OpenGLConstants', + 'OpenGLTypes' + ], + #category : #'Diya-OpenGL' +} + +{ #category : #accessing } +Uniform1i >> setUniformValue [ + OpenGLSLUniform uniform1i: location value: value +] diff --git a/Diya/Uniform2F.class.st b/Diya/Uniform2F.class.st new file mode 100644 index 0000000..c196654 --- /dev/null +++ b/Diya/Uniform2F.class.st @@ -0,0 +1,14 @@ +Class { + #name : #Uniform2F, + #superclass : #OpenGLSLUniform, + #pools : [ + 'OpenGLConstants', + 'OpenGLTypes' + ], + #category : #'Diya-OpenGL' +} + +{ #category : #accessing } +Uniform2F >> setUniformValue [ + OpenGLSLUniform uniform2f: location value: value first value: value last +] diff --git a/Diya/Uniform2i.class.st b/Diya/Uniform2i.class.st new file mode 100644 index 0000000..58266ab --- /dev/null +++ b/Diya/Uniform2i.class.st @@ -0,0 +1,14 @@ +Class { + #name : #Uniform2i, + #superclass : #OpenGLSLUniform, + #pools : [ + 'OpenGLConstants', + 'OpenGLTypes' + ], + #category : #'Diya-OpenGL' +} + +{ #category : #accessing } +Uniform2i >> setUniformValue [ + OpenGLSLUniform uniform2i: location value: value first value: value last +] diff --git a/Diya/Uniform3F.class.st b/Diya/Uniform3F.class.st new file mode 100644 index 0000000..69aa0e5 --- /dev/null +++ b/Diya/Uniform3F.class.st @@ -0,0 +1,14 @@ +Class { + #name : #Uniform3F, + #superclass : #OpenGLSLUniform, + #pools : [ + 'OpenGLConstants', + 'OpenGLTypes' + ], + #category : #'Diya-OpenGL' +} + +{ #category : #accessing } +Uniform3F >> setUniformValue [ + OpenGLSLUniform uniform3f: location value: value first value: (value at:2) value: value last +] diff --git a/Diya/Uniform3i.class.st b/Diya/Uniform3i.class.st new file mode 100644 index 0000000..68b912a --- /dev/null +++ b/Diya/Uniform3i.class.st @@ -0,0 +1,14 @@ +Class { + #name : #Uniform3i, + #superclass : #OpenGLSLUniform, + #pools : [ + 'OpenGLConstants', + 'OpenGLTypes' + ], + #category : #'Diya-OpenGL' +} + +{ #category : #accessing } +Uniform3i >> setUniformValue [ + OpenGLSLUniform uniform3i: location value: value first value: (value at:2) value: value last +] diff --git a/Diya/Uniform4F.class.st b/Diya/Uniform4F.class.st new file mode 100644 index 0000000..9dd3236 --- /dev/null +++ b/Diya/Uniform4F.class.st @@ -0,0 +1,18 @@ +Class { + #name : #Uniform4F, + #superclass : #OpenGLSLUniform, + #pools : [ + 'OpenGLConstants', + 'OpenGLTypes' + ], + #category : #'Diya-OpenGL' +} + +{ #category : #accessing } +Uniform4F >> setUniformValue [ + OpenGLSLUniform uniform4f: location + value: value first + value: (value at:2) + value: (value at:3) + value: value last +] diff --git a/Diya/Uniform4i.class.st b/Diya/Uniform4i.class.st new file mode 100644 index 0000000..60661eb --- /dev/null +++ b/Diya/Uniform4i.class.st @@ -0,0 +1,18 @@ +Class { + #name : #Uniform4i, + #superclass : #OpenGLSLUniform, + #pools : [ + 'OpenGLConstants', + 'OpenGLTypes' + ], + #category : #'Diya-OpenGL' +} + +{ #category : #accessing } +Uniform4i >> setUniformValue [ + OpenGLSLUniform uniform4i: location + value: value first + value: (value at:2) + value: (value at:3) + value: value last +]