├── settings.gradle ├── screenshots ├── texture-gl3.png ├── texture-gl4.png ├── triangle-gl3.png └── triangle-gl4.png ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── src └── main │ ├── resources │ ├── images │ │ ├── door.png │ │ └── globe.png │ └── shaders │ │ ├── gl3 │ │ ├── semantic.glsl │ │ ├── hello-triangle.frag │ │ ├── hello-texture.frag │ │ ├── hello-texture.vert │ │ └── hello-triangle.vert │ │ └── gl4 │ │ ├── hello-globe.frag │ │ ├── hello-triangle.frag │ │ ├── semantic.glsl │ │ ├── hello-globe.vert │ │ └── hello-triangle.vert │ ├── java │ ├── framework │ │ └── Semantic.java │ ├── gl3 │ │ ├── GL_injection.java │ │ ├── Input_into_rendering.java │ │ ├── HelloTriangle.java │ │ ├── HelloTriangleSimple.java │ │ └── HelloTexture.java │ └── gl4 │ │ ├── HelloTriangle.java │ │ ├── HelloTriangleSimple.java │ │ └── HelloGlobe.java │ └── kotlin │ ├── gl3 │ ├── gl_injection.kt │ ├── input_into_rendering.kt │ ├── helloTriangle.kt │ └── helloTexture.kt │ └── gl4 │ ├── helloTriangle.kt │ └── helloGlobe.kt ├── LICENSE ├── gradlew.bat ├── README.md └── gradlew /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.buildFileName = 'build.gradle' 2 | -------------------------------------------------------------------------------- /screenshots/texture-gl3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jvm-graphics-labs/hello-triangle/HEAD/screenshots/texture-gl3.png -------------------------------------------------------------------------------- /screenshots/texture-gl4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jvm-graphics-labs/hello-triangle/HEAD/screenshots/texture-gl4.png -------------------------------------------------------------------------------- /screenshots/triangle-gl3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jvm-graphics-labs/hello-triangle/HEAD/screenshots/triangle-gl3.png -------------------------------------------------------------------------------- /screenshots/triangle-gl4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jvm-graphics-labs/hello-triangle/HEAD/screenshots/triangle-gl4.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jvm-graphics-labs/hello-triangle/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/resources/images/door.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jvm-graphics-labs/hello-triangle/HEAD/src/main/resources/images/door.png -------------------------------------------------------------------------------- /src/main/resources/images/globe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jvm-graphics-labs/hello-triangle/HEAD/src/main/resources/images/globe.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Feb 07 21:38:00 CET 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip 7 | -------------------------------------------------------------------------------- /src/main/resources/shaders/gl3/semantic.glsl: -------------------------------------------------------------------------------- 1 | // Attributes 2 | 3 | #define POSITION 0 4 | #define COLOR 1 5 | #define NORMAL 2 6 | #define TEXCOORD 3 7 | #define DRAW_ID 4 8 | 9 | // Outputs 10 | #define FRAG_COLOR 0 11 | 12 | layout(std140, column_major) uniform; -------------------------------------------------------------------------------- /src/main/resources/shaders/gl4/hello-globe.frag: -------------------------------------------------------------------------------- 1 | 2 | #version 450 core 3 | 4 | #include semantic.glsl 5 | 6 | 7 | layout (binding = DIFFUSE) uniform sampler2D globe; 8 | 9 | 10 | in Block 11 | { 12 | vec2 texCoord_; 13 | }; 14 | 15 | 16 | layout(location = FRAG_COLOR, index = 0) out vec4 color; 17 | 18 | 19 | void main() 20 | { 21 | color = texture(globe, texCoord_); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/shaders/gl3/hello-triangle.frag: -------------------------------------------------------------------------------- 1 | 2 | #version 330 3 | 4 | 5 | #include semantic.glsl 6 | 7 | 8 | // Incoming interpolated (between vertices) color from the vertex shader. 9 | in vec3 interpolatedColor; 10 | 11 | 12 | // Outgoing final color. 13 | layout (location = FRAG_COLOR) out vec4 outputColor; 14 | 15 | 16 | void main() 17 | { 18 | // We simply pad the interpolatedColor to vec4 19 | outputColor = vec4(interpolatedColor, 1); 20 | } 21 | -------------------------------------------------------------------------------- /src/main/resources/shaders/gl4/hello-triangle.frag: -------------------------------------------------------------------------------- 1 | 2 | #version 450 3 | 4 | 5 | #include semantic.glsl 6 | 7 | 8 | // Incoming interpolated (between vertices) color. 9 | layout (location = BLOCK) in Block 10 | { 11 | vec3 interpolatedColor; 12 | }; 13 | 14 | // Outgoing final color. 15 | layout (location = FRAG_COLOR) out vec4 outputColor; 16 | 17 | 18 | void main() 19 | { 20 | // We simply pad the interpolatedColor 21 | outputColor = vec4(interpolatedColor, 1); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/shaders/gl3/hello-texture.frag: -------------------------------------------------------------------------------- 1 | 2 | #version 330 3 | 4 | 5 | #include semantic.glsl 6 | 7 | 8 | // Incoming interpolated (between vertices) texture coordinates. 9 | in vec2 interpolatedTexCoord; 10 | 11 | 12 | // Uniform 2D sampler for our texture object. 13 | uniform sampler2D diffuse; 14 | 15 | 16 | // Outgoing final color. 17 | layout (location = FRAG_COLOR) out vec4 outputColor; 18 | 19 | 20 | void main() 21 | { 22 | // We sample texture0 at the interpolatedTexCoord 23 | outputColor = texture(diffuse, interpolatedTexCoord); 24 | } 25 | -------------------------------------------------------------------------------- /src/main/resources/shaders/gl4/semantic.glsl: -------------------------------------------------------------------------------- 1 | 2 | // Attributes 3 | #define POSITION 0 4 | #define COLOR 1 5 | #define NORMAL 2 6 | #define TEXCOORD 3 7 | #define DRAW_ID 4 8 | 9 | // Uniform 10 | #define TRANSFORM0 1 11 | #define TRANSFORM1 2 12 | 13 | // Samplers 14 | #define DIFFUSE 0 15 | 16 | // Interfaces 17 | #define BLOCK 0 18 | 19 | // Outputs 20 | #define FRAG_COLOR 0 21 | 22 | 23 | precision highp float; 24 | precision highp int; 25 | 26 | layout(std140, column_major) uniform; 27 | layout(std430, column_major) buffer; 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/main/resources/shaders/gl3/hello-texture.vert: -------------------------------------------------------------------------------- 1 | 2 | #version 330 3 | 4 | 5 | #include semantic.glsl 6 | 7 | 8 | // Incoming vertex position, Model Space 9 | layout (location = POSITION) in vec2 position; 10 | 11 | // Incoming vertex color 12 | layout (location = TEXCOORD) in vec2 texCoord; 13 | 14 | 15 | uniform GlobalMatrices 16 | { 17 | mat4 proj; 18 | mat4 view; 19 | }; 20 | 21 | 22 | // Uniform matrix from Model Space to camera (also known as view) Space 23 | uniform mat4 model; 24 | 25 | 26 | // Outgoing texture coordinates. 27 | out vec2 interpolatedTexCoord; 28 | 29 | 30 | void main() { 31 | 32 | // Normally gl_Position is in Clip Space and we calculate it by multiplying together all the matrices 33 | gl_Position = proj * (view * (model * vec4(position, 0, 1))); 34 | 35 | // We assign the texture coordinate to the outgoing variable. 36 | interpolatedTexCoord = texCoord; 37 | } -------------------------------------------------------------------------------- /src/main/resources/shaders/gl3/hello-triangle.vert: -------------------------------------------------------------------------------- 1 | 2 | #version 330 3 | 4 | 5 | #include semantic.glsl 6 | 7 | 8 | // Incoming vertex position, Model Space 9 | layout (location = POSITION) in vec2 position; 10 | 11 | // Incoming vertex color 12 | layout (location = COLOR) in vec3 color; 13 | 14 | 15 | uniform GlobalMatrices 16 | { 17 | mat4 view; 18 | mat4 proj; 19 | }; 20 | 21 | 22 | // Uniform matrix from Model Space to camera (also known as view) Space 23 | uniform mat4 model; 24 | 25 | 26 | // Outgoing color for the next shader (fragment in this case) 27 | out vec3 interpolatedColor; 28 | 29 | 30 | void main() { 31 | 32 | // Normally gl_Position is in Clip Space and we calculate it by multiplying together all the matrices 33 | gl_Position = proj * (view * (model * vec4(position, 0, 1))); 34 | 35 | // We assign the color to the outgoing variable. 36 | interpolatedColor = color; 37 | } 38 | -------------------------------------------------------------------------------- /src/main/resources/shaders/gl4/hello-globe.vert: -------------------------------------------------------------------------------- 1 | 2 | #version 450 core 3 | 4 | #include semantic.glsl 5 | 6 | 7 | // Incoming vertex position, Model Space. 8 | layout (location = POSITION) in vec3 position; 9 | 10 | // Incoming texture coordinate. 11 | layout (location = TEXCOORD) in vec2 texCoord; 12 | 13 | 14 | // Projection and view matrices. 15 | layout (binding = TRANSFORM0) uniform Transform0 16 | { 17 | mat4 proj; 18 | mat4 view; 19 | }; 20 | 21 | // model matrix 22 | layout (binding = TRANSFORM1) uniform Transform1 23 | { 24 | mat4 model; 25 | }; 26 | 27 | 28 | out gl_PerVertex 29 | { 30 | vec4 gl_Position; 31 | }; 32 | 33 | out Block 34 | { 35 | vec2 texCoord_; 36 | }; 37 | 38 | void main() 39 | { 40 | //gl_Position = vec4(0.5f * (gl_VertexID % 2) - 0.5f, 0.5f * (gl_VertexID / 2) - 0.5f, 0.0, 1.0); 41 | gl_Position = proj * (view * (model * vec4(position, 1))); 42 | 43 | texCoord_ = texCoord; 44 | } 45 | -------------------------------------------------------------------------------- /src/main/resources/shaders/gl4/hello-triangle.vert: -------------------------------------------------------------------------------- 1 | 2 | #version 450 3 | 4 | #include semantic.glsl 5 | 6 | // Incoming vertex position, Model Space. 7 | layout (location = POSITION) in vec2 position; 8 | 9 | // Incoming vertex color. 10 | layout (location = COLOR) in vec3 color; 11 | 12 | // Projection and view matrices. 13 | layout (binding = TRANSFORM0) uniform Transform0 14 | { 15 | mat4 proj; 16 | mat4 view; 17 | }; 18 | 19 | // model matrix 20 | layout (binding = TRANSFORM1) uniform Transform1 21 | { 22 | mat4 model; 23 | }; 24 | 25 | // Outgoing color. 26 | layout (location = BLOCK) out Block 27 | { 28 | vec3 interpolatedColor; 29 | }; 30 | 31 | void main() { 32 | 33 | // Normally gl_Position is in Clip Space and we calculate it by multiplying together all the matrices 34 | gl_Position = proj * (view * (model * vec4(position, 0, 1))); 35 | 36 | // We assign the color to the outgoing variable. 37 | interpolatedColor = color; 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Giuseppe Barbieri 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/main/java/framework/Semantic.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this license header, choose License Headers in Project Properties. 3 | * To change this template file, choose Tools | Templates 4 | * and open the template in the editor. 5 | */ 6 | package framework; 7 | 8 | /** 9 | * @author gbarbieri 10 | */ 11 | abstract public class Semantic { 12 | 13 | public interface Attr { 14 | 15 | int POSITION = 0; 16 | int COLOR = 1; 17 | int NORMAL = 2; 18 | int TEXCOORD = 3; 19 | int DRAW_ID = 4; 20 | } 21 | 22 | public interface Buffer { 23 | 24 | int STATIC = 0; 25 | int DYNAMIC = 1; 26 | } 27 | 28 | public interface Frag { 29 | 30 | int COLOR = 0; 31 | int RED = 0; 32 | int GREEN = 1; 33 | int BLUE = 2; 34 | int ALPHA = 0; 35 | } 36 | 37 | public interface Image { 38 | 39 | int DIFFUSE = 0; 40 | int PICKING = 1; 41 | } 42 | 43 | public interface Object { 44 | 45 | int VAO = 0; 46 | int VBO = 1; 47 | int IBO = 2; 48 | int TEXTURE = 3; 49 | int SAMPLER = 4; 50 | int SIZE = 5; 51 | } 52 | 53 | public interface Renderbuffer { 54 | 55 | int DEPTH = 0; 56 | int COLOR0 = 1; 57 | } 58 | 59 | public interface Sampler { 60 | 61 | int DIFFUSE = 0; 62 | int POSITION = 4; 63 | int TEXCOORD = 5; 64 | int COLOR = 6; 65 | } 66 | 67 | public interface Storage { 68 | 69 | int VERTEX = 0; 70 | } 71 | 72 | public interface Uniform { 73 | 74 | int MATERIAL = 0; 75 | int TRANSFORM0 = 1; 76 | int TRANSFORM1 = 2; 77 | int INDIRECTION = 3; 78 | int GLOBAL_MATRICES = 4; 79 | int CONSTANT = 0; 80 | int PER_FRAME = 1; 81 | int PER_PASS = 2; 82 | int LIGHT = 3; 83 | } 84 | 85 | public interface Vert { 86 | 87 | int POSITION = 0; 88 | int COLOR = 3; 89 | int TEXCOORD = 4; 90 | int INSTANCE = 7; 91 | } 92 | 93 | public interface Stream { 94 | 95 | int A = 0; 96 | int B = 1; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /src/main/kotlin/gl3/gl_injection.kt: -------------------------------------------------------------------------------- 1 | package gl3 2 | 3 | import com.jogamp.newt.event.KeyEvent 4 | import com.jogamp.newt.event.KeyListener 5 | import com.jogamp.newt.event.WindowAdapter 6 | import com.jogamp.newt.event.WindowEvent 7 | import com.jogamp.newt.opengl.GLWindow 8 | import com.jogamp.opengl.* 9 | import com.jogamp.opengl.GL2ES3.GL_COLOR 10 | import com.jogamp.opengl.util.Animator 11 | import com.jogamp.opengl.util.GLBuffers 12 | import glm.set 13 | import uno.buffer.toFloatBuffer 14 | 15 | /** 16 | * Created by GBarbieri on 27.03.2017. 17 | */ 18 | 19 | fun main(args: Array) { 20 | GL_injection_().setup() 21 | } 22 | 23 | class GL_injection_ : GLEventListener, KeyListener { 24 | 25 | lateinit var window: GLWindow 26 | lateinit var animator:Animator 27 | 28 | val clearColor = floatArrayOf(0f, 0f, 0f, 0f).toFloatBuffer() 29 | 30 | fun setup() { 31 | 32 | val glProfile = GLProfile.get(GLProfile.GL3) 33 | val glCapabilities = GLCapabilities(glProfile) 34 | 35 | window = GLWindow.create(glCapabilities) 36 | 37 | window.title = "gl injection" 38 | window.setSize(1024, 768) 39 | 40 | window.addGLEventListener(this) 41 | window.addKeyListener(this) 42 | 43 | window.autoSwapBufferMode = false 44 | 45 | window.isVisible = true 46 | 47 | animator = Animator(window) 48 | animator.start() 49 | 50 | window.addWindowListener(object : WindowAdapter() { 51 | override fun windowDestroyed(e: WindowEvent?) { 52 | animator.stop() 53 | System.exit(1) 54 | } 55 | }) 56 | } 57 | 58 | override fun init(drawable: GLAutoDrawable) {} 59 | 60 | override fun reshape(drawable: GLAutoDrawable, x: Int, y: Int, width: Int, height: Int) {} 61 | 62 | override fun display(drawable: GLAutoDrawable) {} 63 | 64 | override fun dispose(drawable: GLAutoDrawable) {} 65 | 66 | override fun keyPressed(e: KeyEvent) { 67 | 68 | if (e.keyCode == KeyEvent.VK_ESCAPE) 69 | Thread { window.destroy() }.start() 70 | 71 | when (e.keyCode) { 72 | KeyEvent.VK_R -> modified(0) 73 | KeyEvent.VK_G -> modified(1) 74 | KeyEvent.VK_B -> modified(2) 75 | KeyEvent.VK_A -> modified(3) 76 | } 77 | } 78 | 79 | fun modified(index: Int) { 80 | clearColor[index] = if (clearColor[index] == 0f) 1f else 0f 81 | println("clear color: (" + clearColor[0] + ", " + clearColor[1] + ", " + clearColor[2] + ", " + clearColor[3] + ")") 82 | window.invoke(false) { drawable -> 83 | drawable.gl.gL3.glClearBufferfv(GL_COLOR, 0, clearColor) 84 | drawable.swapBuffers() 85 | true 86 | } 87 | } 88 | 89 | override fun keyReleased(e: KeyEvent) {} 90 | } -------------------------------------------------------------------------------- /src/main/kotlin/gl3/input_into_rendering.kt: -------------------------------------------------------------------------------- 1 | package gl3 2 | 3 | import com.jogamp.newt.event.* 4 | import com.jogamp.newt.opengl.GLWindow 5 | import com.jogamp.opengl.* 6 | import com.jogamp.opengl.GL2ES3.GL_COLOR 7 | import com.jogamp.opengl.util.Animator 8 | import com.jogamp.opengl.util.GLBuffers 9 | import glm.set 10 | import uno.buffer.toFloatBuffer 11 | 12 | /** 13 | * Created by GBarbieri on 27.03.2017. 14 | */ 15 | 16 | fun main(args: Array) { 17 | Input_into_rendering_().initGL() 18 | } 19 | 20 | class Input_into_rendering_ : GLEventListener, KeyListener { 21 | 22 | lateinit var window: GLWindow 23 | lateinit var animator: Animator 24 | 25 | val clearColor = floatArrayOf(0f, 0f, 0f, 0f).toFloatBuffer() 26 | 27 | val eventFiFo = NEWTEventFiFo() 28 | 29 | fun initGL() { 30 | 31 | val glProfile = GLProfile.get(GLProfile.GL3) 32 | val glCapabilities = GLCapabilities(glProfile) 33 | 34 | window = GLWindow.create(glCapabilities) 35 | 36 | window.title = "Input into rendering" 37 | window.setSize(1024, 768) 38 | 39 | window.addGLEventListener(this) 40 | window.addKeyListener(this) 41 | 42 | window.isVisible = true 43 | 44 | animator = Animator(window) 45 | animator.start() 46 | 47 | window.addWindowListener(object : WindowAdapter() { 48 | override fun windowDestroyed(e: WindowEvent?) { 49 | animator.stop() 50 | System.exit(1) 51 | } 52 | }) 53 | } 54 | 55 | override fun init(drawable: GLAutoDrawable) {} 56 | 57 | override fun reshape(drawable: GLAutoDrawable, x: Int, y: Int, width: Int, height: Int) {} 58 | 59 | override fun display(drawable: GLAutoDrawable) { 60 | 61 | val gl = drawable.gl.gL3 62 | 63 | var event = eventFiFo.get() 64 | while (event != null) { 65 | if (event is KeyEvent && event.eventType == KeyEvent.EVENT_KEY_PRESSED) 66 | when (event.keyCode) { 67 | KeyEvent.VK_R -> modified(0) 68 | KeyEvent.VK_G -> modified(1) 69 | KeyEvent.VK_B -> modified(2) 70 | KeyEvent.VK_A -> modified(3) 71 | } 72 | event = eventFiFo.get() 73 | } 74 | 75 | gl.glClearBufferfv(GL_COLOR, 0, clearColor) 76 | } 77 | 78 | fun modified(index: Int) { 79 | clearColor[index] = if (clearColor.get(index) == 0f) 1f else 0f 80 | println("clear color: (" + clearColor[0] + ", " + clearColor[1] + ", " + clearColor[2] + ", " + clearColor[3] + ")") 81 | } 82 | 83 | override fun dispose(drawable: GLAutoDrawable) {} 84 | 85 | override fun keyPressed(e: KeyEvent) { 86 | 87 | if (e.keyCode == KeyEvent.VK_ESCAPE) 88 | Thread { window.destroy() }.start() 89 | 90 | eventFiFo.put(e) 91 | } 92 | 93 | override fun keyReleased(e: KeyEvent) { 94 | eventFiFo.put(e) 95 | } 96 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Content: 2 | 3 | - OpenGL 4: 4 | - Hello Triangle: 5 | - [Simple Java](https://github.com/java-opengl-labs/helloTriangle/blob/master/src/main/java/gl4/HelloTriangleSimple.java) using pure plain JOGL, without additional libraries 6 | - [Java](https://github.com/java-opengl-labs/helloTriangle/blob/master/src/main/java/gl4/HelloTriangle.java) 7 | - [Kotlin](https://github.com/java-opengl-labs/helloTriangle/blob/master/src/main/kotlin/gl4/helloTriangle.kt) 8 | 9 | - Hello Globe: 10 | - [Java](https://github.com/java-opengl-labs/helloTriangle/blob/master/src/main/java/gl4/HelloGlobe.java) 11 | - [Kotlin](https://github.com/java-opengl-labs/helloTriangle/blob/master/src/main/kotlin/gl4/helloGlobe.kt) 12 | 13 | 14 | 15 | - OpenGL 3: 16 | 17 | - Hello Triangle: 18 | - [Simple Java](https://github.com/java-opengl-labs/helloTriangle/blob/master/src/main/java/gl3/HelloTriangleSimple.java) using pure plain JOGL, without additional libraries 19 | - [Java](https://github.com/java-opengl-labs/helloTriangle/blob/master/src/main/java/gl3/HelloTriangle.java) 20 | - [Kotlin](https://github.com/java-opengl-labs/helloTriangle/blob/master/src/main/kotlin/gl3/helloTriangle.kt) 21 | 22 | - Hello Texture: 23 | - [Java](https://github.com/java-opengl-labs/helloTriangle/blob/master/src/main/java/gl3/HelloTexture.java) 24 | - [Kotlin](https://github.com/java-opengl-labs/helloTriangle/blob/master/src/main/kotlin/gl3/helloTexture.kt) 25 | 26 | - GL injection: shows how to inject GL commands into a GL fifo from another thread (like the input listener): 27 | - [Java](https://github.com/java-opengl-labs/hello-triangle/blob/master/src/main/java/gl3/GL_injection.java) 28 | - [Kotlin](https://github.com/java-opengl-labs/hello-triangle/blob/master/src/main/kotlin/gl3/gl_injection.kt) 29 | 30 | - Input into rendering: shows how to use a fifo stack to pipe events from the EDT (listener) into the rendering loop: 31 | - [Java](https://github.com/java-opengl-labs/hello-triangle/blob/master/src/main/java/gl3/Input_into_rendering.java) 32 | - [Kotlin](https://github.com/java-opengl-labs/hello-triangle/blob/master/src/main/kotlin/gl3/input_into_rendering.kt) 33 | 34 | ## Quick start: 35 | 36 | * clone & sync Gradle 37 | * run it and enjoy the OpenGL acceleration on Java :sunglasses: (or even better, on Kotlin :scream:) 38 | 39 | If you don't know how to use Gradle, follow this simple [tutorial](https://github.com/java-opengl-labs/hello-triangle/wiki/How-to-clone-the-project-and-get-it-running) 40 | 41 | If you have any problem/question/doubt do not hesitate asking on the [jogl forums](http://forum.jogamp.org/) or [StackOverflow](http://stackoverflow.com/) or open an [issue here](https://github.com/elect86/helloTriangle/issues) 42 | 43 | 44 | In case you find the above samples too complex or difficult to understand, I strongly suggest you to start from scratch with a jogl tutorial, such as [modern-jogl-examples](https://github.com/java-opengl-labs/modern-jogl-examples). The original C tutorial it's ported from, it's one of the best, if not the best, out there. 45 | -------------------------------------------------------------------------------- /src/main/java/gl3/GL_injection.java: -------------------------------------------------------------------------------- 1 | package gl3; 2 | 3 | import com.jogamp.newt.event.*; 4 | import com.jogamp.newt.opengl.GLWindow; 5 | import com.jogamp.opengl.*; 6 | import com.jogamp.opengl.util.Animator; 7 | import com.jogamp.opengl.util.GLBuffers; 8 | 9 | import java.nio.FloatBuffer; 10 | 11 | import static com.jogamp.opengl.GL2ES3.GL_COLOR; 12 | 13 | /** 14 | * Created by GBarbieri on 27.03.2017. 15 | */ 16 | public class GL_injection implements GLEventListener, KeyListener { 17 | 18 | private static GLWindow window; 19 | private static Animator animator; 20 | 21 | public static void main(String[] args) { 22 | new GL_injection().setup(); 23 | } 24 | 25 | private FloatBuffer clearColor = GLBuffers.newDirectFloatBuffer(new float[]{0, 0, 0, 0}); 26 | 27 | private void setup() { 28 | 29 | GLProfile glProfile = GLProfile.get(GLProfile.GL3); 30 | GLCapabilities glCapabilities = new GLCapabilities(glProfile); 31 | 32 | window = GLWindow.create(glCapabilities); 33 | 34 | window.setTitle("gl injection"); 35 | window.setSize(1024, 768); 36 | 37 | window.addGLEventListener(this); 38 | window.addKeyListener(this); 39 | 40 | window.setAutoSwapBufferMode(false); 41 | 42 | window.setVisible(true); 43 | 44 | animator = new Animator(window); 45 | animator.start(); 46 | 47 | window.addWindowListener(new WindowAdapter() { 48 | @Override 49 | public void windowDestroyed(WindowEvent e) { 50 | animator.stop(); 51 | System.exit(1); 52 | } 53 | }); 54 | } 55 | 56 | @Override 57 | public void init(GLAutoDrawable drawable) { 58 | } 59 | 60 | @Override 61 | public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { 62 | } 63 | 64 | @Override 65 | public void display(GLAutoDrawable drawable) { 66 | } 67 | 68 | @Override 69 | public void dispose(GLAutoDrawable drawable) { 70 | } 71 | 72 | @Override 73 | public void keyPressed(KeyEvent e) { 74 | 75 | if (e.getKeyCode() == KeyEvent.VK_ESCAPE) 76 | new Thread(() -> { 77 | window.destroy(); 78 | }).start(); 79 | 80 | switch (e.getKeyCode()) { 81 | case KeyEvent.VK_R: 82 | modified(0); 83 | break; 84 | case KeyEvent.VK_G: 85 | modified(1); 86 | break; 87 | case KeyEvent.VK_B: 88 | modified(2); 89 | break; 90 | case KeyEvent.VK_A: 91 | modified(3); 92 | break; 93 | } 94 | } 95 | 96 | private void modified(int index) { 97 | clearColor.put(index, (clearColor.get(index) == 0) ? 1 : 0); 98 | System.out.println("clear color: (" + clearColor.get(0) + ", " + clearColor.get(1) + ", " + clearColor.get(2) + ", " + clearColor.get(3) + ")"); 99 | window.invoke(false, new GLRunnable() { 100 | @Override 101 | public boolean run(GLAutoDrawable drawable) { 102 | drawable.getGL().getGL3().glClearBufferfv(GL_COLOR, 0, clearColor); 103 | drawable.swapBuffers(); 104 | return true; 105 | } 106 | }); 107 | } 108 | 109 | 110 | @Override 111 | public void keyReleased(KeyEvent e) { 112 | } 113 | } -------------------------------------------------------------------------------- /src/main/java/gl3/Input_into_rendering.java: -------------------------------------------------------------------------------- 1 | package gl3; 2 | 3 | import com.jogamp.newt.event.*; 4 | import com.jogamp.newt.opengl.GLWindow; 5 | import com.jogamp.opengl.*; 6 | import com.jogamp.opengl.util.Animator; 7 | import com.jogamp.opengl.util.GLBuffers; 8 | 9 | import java.nio.FloatBuffer; 10 | 11 | import static com.jogamp.opengl.GL2ES3.GL_COLOR; 12 | 13 | /** 14 | * Created by GBarbieri on 27.03.2017. 15 | */ 16 | public class Input_into_rendering implements GLEventListener, KeyListener { 17 | 18 | private static GLWindow window; 19 | private static Animator animator; 20 | 21 | public static void main(String[] args) { 22 | new Input_into_rendering().setup(); 23 | } 24 | 25 | private FloatBuffer clearColor = GLBuffers.newDirectFloatBuffer(new float[]{0, 0, 0, 0}); 26 | 27 | private NEWTEventFiFo eventFiFo = new NEWTEventFiFo(); 28 | 29 | private void setup() { 30 | 31 | GLProfile glProfile = GLProfile.get(GLProfile.GL3); 32 | GLCapabilities glCapabilities = new GLCapabilities(glProfile); 33 | 34 | window = GLWindow.create(glCapabilities); 35 | 36 | window.setTitle("Input into rendering"); 37 | window.setSize(1024, 768); 38 | 39 | window.addGLEventListener(this); 40 | window.addKeyListener(this); 41 | 42 | window.setVisible(true); 43 | 44 | animator = new Animator(window); 45 | animator.start(); 46 | 47 | window.addWindowListener(new WindowAdapter() { 48 | @Override 49 | public void windowDestroyed(WindowEvent e) { 50 | animator.stop(); 51 | System.exit(1); 52 | } 53 | }); 54 | } 55 | 56 | @Override 57 | public void init(GLAutoDrawable drawable) { 58 | } 59 | 60 | @Override 61 | public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { 62 | } 63 | 64 | @Override 65 | public void display(GLAutoDrawable drawable) { 66 | 67 | GL3 gl = drawable.getGL().getGL3(); 68 | 69 | NEWTEvent event = eventFiFo.get(); 70 | while (event != null) { 71 | if (event instanceof KeyEvent) { 72 | KeyEvent keyEvent = (KeyEvent) event; 73 | if (keyEvent.getEventType() == KeyEvent.EVENT_KEY_PRESSED) 74 | switch (keyEvent.getKeyCode()) { 75 | case KeyEvent.VK_R: 76 | modified(0); 77 | break; 78 | case KeyEvent.VK_G: 79 | modified(1); 80 | break; 81 | case KeyEvent.VK_B: 82 | modified(2); 83 | break; 84 | case KeyEvent.VK_A: 85 | modified(3); 86 | break; 87 | } 88 | } 89 | event = eventFiFo.get(); 90 | } 91 | 92 | gl.glClearBufferfv(GL_COLOR, 0, clearColor); 93 | } 94 | 95 | private void modified(int index) { 96 | clearColor.put(index, (clearColor.get(index) == 0) ? 1 : 0); 97 | System.out.println("clear color: (" + clearColor.get(0) + ", " + clearColor.get(1) + ", " + clearColor.get(2) + ", " + clearColor.get(3) + ")"); 98 | } 99 | 100 | @Override 101 | public void dispose(GLAutoDrawable drawable) { 102 | } 103 | 104 | @Override 105 | public void keyPressed(KeyEvent e) { 106 | 107 | if (e.getKeyCode() == KeyEvent.VK_ESCAPE) 108 | new Thread(() -> { 109 | window.destroy(); 110 | }).start(); 111 | 112 | eventFiFo.put(e); 113 | } 114 | 115 | @Override 116 | public void keyReleased(KeyEvent e) { 117 | eventFiFo.put(e); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /src/main/kotlin/gl3/helloTriangle.kt: -------------------------------------------------------------------------------- 1 | package gl3 2 | 3 | import com.jogamp.newt.event.KeyEvent 4 | import com.jogamp.newt.event.KeyListener 5 | import com.jogamp.newt.event.WindowAdapter 6 | import com.jogamp.newt.event.WindowEvent 7 | import com.jogamp.newt.opengl.GLWindow 8 | import com.jogamp.opengl.* 9 | import com.jogamp.opengl.GL2ES2.GL_STREAM_DRAW 10 | import com.jogamp.opengl.GL2ES3.* 11 | import com.jogamp.opengl.util.Animator 12 | import framework.Semantic 13 | import glm.L 14 | import glm.SIZE 15 | import glm.f 16 | import glm.glm 17 | import glm.mat.Mat4 18 | import glm.vec._2.Vec2 19 | import glm.vec._3.Vec3 20 | import uno.buffer.* 21 | import uno.gl.checkError 22 | import uno.glsl.Program 23 | import kotlin.properties.Delegates 24 | 25 | /** 26 | * Created by elect on 05/03/17. 27 | */ 28 | 29 | fun main(args: Array) { 30 | HelloTriangleK().setup() 31 | } 32 | 33 | class HelloTriangleK : GLEventListener, KeyListener { 34 | 35 | var window by Delegates.notNull() 36 | val animator = Animator() 37 | 38 | val vertexData = floatArrayOf( 39 | -1f, -1f, 1f, 0f, 0f, 40 | +0f, +2f, 0f, 0f, 1f, 41 | +1f, -1f, 0f, 1f, 0f) 42 | 43 | val elementData = shortArrayOf(0, 2, 1) 44 | 45 | object Buffer { 46 | val VERTEX = 0 47 | val ELEMENT = 1 48 | val GLOBAL_MATRICES = 2 49 | val MAX = 3 50 | } 51 | 52 | val bufferName = intBufferBig(Buffer.MAX) 53 | val vertexArrayName = intBufferBig(1) 54 | 55 | val clearColor = floatBufferBig(4) 56 | val clearDepth = floatBufferBig(1) 57 | 58 | val matBuffer = floatBufferBig(16) 59 | 60 | var program by Delegates.notNull() 61 | 62 | var start = 0L 63 | 64 | fun setup() { 65 | 66 | val glProfile = GLProfile.get(GLProfile.GL3) 67 | val glCapabilities = GLCapabilities(glProfile) 68 | 69 | window = GLWindow.create(glCapabilities) 70 | 71 | window.title = "Hello Triangle" 72 | window.setSize(1024, 768) 73 | 74 | window.isVisible = true 75 | 76 | window.addGLEventListener(this) 77 | window.addKeyListener(this) 78 | 79 | animator.add(window) 80 | animator.start() 81 | 82 | window.addWindowListener(object : WindowAdapter() { 83 | override fun windowDestroyed(e: WindowEvent?) { 84 | animator.stop(); System.exit(1); } 85 | }) 86 | } 87 | 88 | override fun init(drawable: GLAutoDrawable) { 89 | 90 | val gl = drawable.gl.gL3 91 | 92 | initBuffers(gl) 93 | 94 | initVertexArray(gl) 95 | 96 | initProgram(gl) 97 | 98 | gl.glEnable(GL_DEPTH_TEST) 99 | 100 | start = System.currentTimeMillis() 101 | } 102 | 103 | fun initBuffers(gl: GL3) = with(gl) { 104 | 105 | val vertexBuffer = vertexData.toFloatBuffer() 106 | val elementBuffer = elementData.toShortBuffer() 107 | 108 | glGenBuffers(Buffer.MAX, bufferName) 109 | 110 | glBindBuffer(GL_ARRAY_BUFFER, bufferName[Buffer.VERTEX]) 111 | glBufferData(GL_ARRAY_BUFFER, vertexBuffer.SIZE.L, vertexBuffer, GL_STATIC_DRAW) 112 | glBindBuffer(GL_ARRAY_BUFFER, 0) 113 | 114 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferName[Buffer.ELEMENT]) 115 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementBuffer.SIZE.L, elementBuffer, GL_STATIC_DRAW) 116 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) 117 | 118 | 119 | glBindBuffer(GL_UNIFORM_BUFFER, bufferName[Buffer.GLOBAL_MATRICES]) 120 | glBufferData(GL_UNIFORM_BUFFER, Mat4.SIZE.L * 2, null, GL_STREAM_DRAW) 121 | glBindBuffer(GL_UNIFORM_BUFFER, 0) 122 | 123 | glBindBufferBase(GL_UNIFORM_BUFFER, Semantic.Uniform.GLOBAL_MATRICES, bufferName[Buffer.GLOBAL_MATRICES]) 124 | 125 | 126 | destroyBuffers(vertexBuffer, elementBuffer) 127 | 128 | checkError(gl, "initBuffers") 129 | } 130 | 131 | fun initVertexArray(gl: GL3) = with(gl) { 132 | 133 | glGenVertexArrays(1, vertexArrayName) 134 | glBindVertexArray(vertexArrayName[0]) 135 | 136 | run { 137 | 138 | glBindBuffer(GL_ARRAY_BUFFER, bufferName[Buffer.VERTEX]) 139 | 140 | run { 141 | val stride = Vec2.SIZE + Vec3.SIZE 142 | var offset = 0 143 | 144 | glEnableVertexAttribArray(Semantic.Attr.POSITION) 145 | glVertexAttribPointer(Semantic.Attr.POSITION, Vec2.length, GL_FLOAT, false, stride, offset.L) 146 | 147 | offset = Vec2.SIZE 148 | glEnableVertexAttribArray(Semantic.Attr.COLOR) 149 | glVertexAttribPointer(Semantic.Attr.COLOR, Vec3.length, GL_FLOAT, false, stride, offset.L) 150 | } 151 | glBindBuffer(GL_ARRAY_BUFFER, 0) 152 | 153 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferName[Buffer.ELEMENT]) 154 | } 155 | glBindVertexArray(0) 156 | 157 | checkError(gl, "initVao") 158 | } 159 | 160 | fun initProgram(gl: GL3) = with(gl) { 161 | 162 | program = Program(gl, this::class.java, "shaders/gl3", "hello-triangle.vert", "hello-triangle.frag", "model") 163 | 164 | val globalMatricesBI = glGetUniformBlockIndex(program.name, "GlobalMatrices") 165 | 166 | if (globalMatricesBI == -1) { 167 | System.err.println("block index 'GlobalMatrices' not found!") 168 | } 169 | glUniformBlockBinding(program.name, globalMatricesBI, Semantic.Uniform.GLOBAL_MATRICES) 170 | 171 | checkError(gl, "initProgram") 172 | } 173 | 174 | override fun display(drawable: GLAutoDrawable) = with(drawable.gl.gL3) { 175 | 176 | // view matrix 177 | run { 178 | val view = Mat4() 179 | 180 | view to matBuffer 181 | 182 | glBindBuffer(GL_UNIFORM_BUFFER, bufferName[Buffer.GLOBAL_MATRICES]) 183 | glBufferSubData(GL_UNIFORM_BUFFER, Mat4.SIZE.L, Mat4.SIZE.L, matBuffer) 184 | glBindBuffer(GL_UNIFORM_BUFFER, 0) 185 | } 186 | 187 | glClearBufferfv(GL_COLOR, 0, clearColor.put(0f, .33f, 0.66f, 1f)) 188 | glClearBufferfv(GL_DEPTH, 0, clearDepth.put(0, 1f)) 189 | 190 | glUseProgram(program.name) 191 | glBindVertexArray(vertexArrayName[0]) 192 | 193 | // model matrix 194 | run { 195 | val now = System.currentTimeMillis() 196 | val diff = (now - start).f / 1_000f 197 | 198 | val model = Mat4() 199 | .scale(0.5f) 200 | .rotate(diff, 0f, 0f, 1f) 201 | 202 | model to matBuffer 203 | 204 | glUniformMatrix4fv(program["model"], 1, false, matBuffer) 205 | } 206 | 207 | glDrawElements(GL_TRIANGLES, elementData.size, GL_UNSIGNED_SHORT, 0) 208 | 209 | glUseProgram(0) 210 | glBindVertexArray(0) 211 | 212 | checkError(drawable.gl, "display") 213 | } 214 | 215 | override fun reshape(drawable: GLAutoDrawable, x: Int, y: Int, width: Int, height: Int) = with(drawable.gl.gL3) { 216 | 217 | val ortho = glm.ortho(-1f, 1f, -1f, 1f, 1f, -1f) 218 | 219 | ortho to matBuffer 220 | 221 | glBindBuffer(GL_UNIFORM_BUFFER, bufferName[Buffer.GLOBAL_MATRICES]) 222 | glBufferSubData(GL_UNIFORM_BUFFER, 0, Mat4.SIZE.L, matBuffer) 223 | glBindBuffer(GL_UNIFORM_BUFFER, 0) 224 | 225 | glViewport(x, y, width, height) 226 | } 227 | 228 | override fun dispose(drawable: GLAutoDrawable) = with(drawable.gl.gL3) { 229 | 230 | glDeleteProgram(program.name) 231 | glDeleteVertexArrays(1, vertexArrayName) 232 | glDeleteBuffers(Buffer.MAX, bufferName) 233 | 234 | destroyBuffers(vertexArrayName, bufferName, matBuffer, clearColor, clearDepth) 235 | } 236 | 237 | 238 | override fun keyPressed(e: KeyEvent) { 239 | 240 | if (e.keyCode == KeyEvent.VK_ESCAPE) { 241 | Thread(Runnable { window.destroy() }).start() 242 | } 243 | } 244 | 245 | override fun keyReleased(e: KeyEvent) {} 246 | } -------------------------------------------------------------------------------- /src/main/java/gl3/HelloTriangle.java: -------------------------------------------------------------------------------- 1 | 2 | package gl3; 3 | 4 | import com.jogamp.newt.event.KeyEvent; 5 | import com.jogamp.newt.event.KeyListener; 6 | import com.jogamp.newt.event.WindowAdapter; 7 | import com.jogamp.newt.event.WindowEvent; 8 | import com.jogamp.newt.opengl.GLWindow; 9 | import com.jogamp.opengl.*; 10 | import com.jogamp.opengl.util.Animator; 11 | import com.jogamp.opengl.util.GLBuffers; 12 | import framework.Semantic; 13 | import glm.mat.Mat4x4; 14 | import glm.vec._2.Vec2; 15 | import glm.vec._3.Vec3; 16 | import uno.glsl.Program; 17 | 18 | import java.nio.FloatBuffer; 19 | import java.nio.IntBuffer; 20 | import java.nio.ShortBuffer; 21 | 22 | import static com.jogamp.opengl.GL.GL_ARRAY_BUFFER; 23 | import static com.jogamp.opengl.GL.GL_DEPTH_TEST; 24 | import static com.jogamp.opengl.GL.GL_ELEMENT_ARRAY_BUFFER; 25 | import static com.jogamp.opengl.GL.GL_FLOAT; 26 | import static com.jogamp.opengl.GL.GL_STATIC_DRAW; 27 | import static com.jogamp.opengl.GL.GL_TRIANGLES; 28 | import static com.jogamp.opengl.GL.GL_UNSIGNED_SHORT; 29 | import static com.jogamp.opengl.GL2ES2.GL_STREAM_DRAW; 30 | import static com.jogamp.opengl.GL2ES3.*; 31 | import static glm.GlmKt.glm; 32 | import static uno.buffer.UtilKt.destroyBuffers; 33 | import static uno.gl.GlErrorKt.checkError; 34 | 35 | /** 36 | * Created by elect on 04/03/17. 37 | */ 38 | 39 | public class HelloTriangle implements GLEventListener, KeyListener { 40 | 41 | private static GLWindow window; 42 | private static Animator animator; 43 | 44 | public static void main(String[] args) { 45 | new HelloTriangle().setup(); 46 | } 47 | 48 | private float[] vertexData = { 49 | -1, -1, 1, 0, 0, 50 | +0, +2, 0, 0, 1, 51 | +1, -1, 0, 1, 0}; 52 | 53 | private short[] elementData = {0, 2, 1}; 54 | 55 | private interface Buffer { 56 | 57 | int VERTEX = 0; 58 | int ELEMENT = 1; 59 | int GLOBAL_MATRICES = 2; 60 | int MAX = 3; 61 | } 62 | 63 | private IntBuffer bufferName = GLBuffers.newDirectIntBuffer(Buffer.MAX); 64 | private IntBuffer vertexArrayName = GLBuffers.newDirectIntBuffer(1); 65 | 66 | private FloatBuffer clearColor = GLBuffers.newDirectFloatBuffer(4); 67 | private FloatBuffer clearDepth = GLBuffers.newDirectFloatBuffer(1); 68 | 69 | private FloatBuffer matBuffer = GLBuffers.newDirectFloatBuffer(16); 70 | 71 | private Program program; 72 | 73 | private long start; 74 | 75 | private void setup() { 76 | 77 | GLProfile glProfile = GLProfile.get(GLProfile.GL3); 78 | GLCapabilities glCapabilities = new GLCapabilities(glProfile); 79 | 80 | window = GLWindow.create(glCapabilities); 81 | 82 | window.setTitle("Hello Triangle (enhanced)"); 83 | window.setSize(1024, 768); 84 | 85 | window.setVisible(true); 86 | 87 | window.addGLEventListener(this); 88 | window.addKeyListener(this); 89 | 90 | animator = new Animator(window); 91 | animator.start(); 92 | 93 | window.addWindowListener(new WindowAdapter() { 94 | @Override 95 | public void windowDestroyed(WindowEvent e) { 96 | animator.stop(); 97 | System.exit(1); 98 | } 99 | }); 100 | } 101 | 102 | @Override 103 | public void init(GLAutoDrawable drawable) { 104 | 105 | GL3 gl = drawable.getGL().getGL3(); 106 | 107 | initBuffers(gl); 108 | 109 | initVertexArray(gl); 110 | 111 | initProgram(gl); 112 | 113 | gl.glEnable(GL_DEPTH_TEST); 114 | 115 | start = System.currentTimeMillis(); 116 | } 117 | 118 | private void initBuffers(GL3 gl) { 119 | 120 | FloatBuffer vertexBuffer = GLBuffers.newDirectFloatBuffer(vertexData); 121 | ShortBuffer elementBuffer = GLBuffers.newDirectShortBuffer(elementData); 122 | 123 | gl.glGenBuffers(Buffer.MAX, bufferName); 124 | 125 | gl.glBindBuffer(GL_ARRAY_BUFFER, bufferName.get(Buffer.VERTEX)); 126 | gl.glBufferData(GL_ARRAY_BUFFER, vertexBuffer.capacity() * Float.BYTES, vertexBuffer, GL_STATIC_DRAW); 127 | gl.glBindBuffer(GL_ARRAY_BUFFER, 0); 128 | 129 | gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferName.get(Buffer.ELEMENT)); 130 | gl.glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementBuffer.capacity() * Short.BYTES, elementBuffer, GL_STATIC_DRAW); 131 | gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 132 | 133 | 134 | gl.glBindBuffer(GL_UNIFORM_BUFFER, bufferName.get(Buffer.GLOBAL_MATRICES)); 135 | gl.glBufferData(GL_UNIFORM_BUFFER, Mat4x4.SIZE * 2, null, GL_STREAM_DRAW); 136 | gl.glBindBuffer(GL_UNIFORM_BUFFER, 0); 137 | 138 | gl.glBindBufferBase(GL_UNIFORM_BUFFER, Semantic.Uniform.GLOBAL_MATRICES, bufferName.get(Buffer.GLOBAL_MATRICES)); 139 | 140 | 141 | destroyBuffers(vertexBuffer, elementBuffer); 142 | 143 | checkError(gl, "initBuffers"); 144 | } 145 | 146 | private void initVertexArray(GL3 gl) { 147 | 148 | gl.glGenVertexArrays(1, vertexArrayName); 149 | gl.glBindVertexArray(vertexArrayName.get(0)); 150 | { 151 | gl.glBindBuffer(GL_ARRAY_BUFFER, bufferName.get(Buffer.VERTEX)); 152 | { 153 | int stride = Vec2.SIZE + Vec3.SIZE; 154 | int offset = 0; 155 | 156 | gl.glEnableVertexAttribArray(Semantic.Attr.POSITION); 157 | gl.glVertexAttribPointer(Semantic.Attr.POSITION, Vec2.length, GL_FLOAT, false, stride, offset); 158 | 159 | offset = Vec2.SIZE; 160 | gl.glEnableVertexAttribArray(Semantic.Attr.COLOR); 161 | gl.glVertexAttribPointer(Semantic.Attr.COLOR, Vec3.length, GL_FLOAT, false, stride, offset); 162 | } 163 | gl.glBindBuffer(GL_ARRAY_BUFFER, 0); 164 | 165 | gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferName.get(Buffer.ELEMENT)); 166 | } 167 | gl.glBindVertexArray(0); 168 | 169 | checkError(gl, "initVao"); 170 | } 171 | 172 | private void initProgram(GL3 gl) { 173 | 174 | program = new Program(gl, getClass(), "shaders/gl3", "hello-triangle.vert", "hello-triangle.frag", "model"); 175 | 176 | int globalMatricesBI = gl.glGetUniformBlockIndex(program.name, "GlobalMatrices"); 177 | 178 | if (globalMatricesBI == -1) { 179 | System.err.println("block index 'GlobalMatrices' not found!"); 180 | } 181 | gl.glUniformBlockBinding(program.name, globalMatricesBI, Semantic.Uniform.GLOBAL_MATRICES); 182 | 183 | checkError(gl, "initProgram"); 184 | } 185 | 186 | @Override 187 | public void display(GLAutoDrawable drawable) { 188 | 189 | GL3 gl = drawable.getGL().getGL3(); 190 | 191 | // view matrix 192 | { 193 | Mat4x4 view = new Mat4x4(); 194 | view.to(matBuffer); 195 | 196 | gl.glBindBuffer(GL_UNIFORM_BUFFER, bufferName.get(Buffer.GLOBAL_MATRICES)); 197 | gl.glBufferSubData(GL_UNIFORM_BUFFER, Mat4x4.SIZE, Mat4x4.SIZE, matBuffer); 198 | gl.glBindBuffer(GL_UNIFORM_BUFFER, 0); 199 | } 200 | 201 | gl.glClearBufferfv(GL_COLOR, 0, clearColor.put(0, 0f).put(1, .33f).put(2, 0.66f).put(3, 1f)); 202 | gl.glClearBufferfv(GL_DEPTH, 0, clearDepth.put(0, 1f)); 203 | 204 | gl.glUseProgram(program.name); 205 | gl.glBindVertexArray(vertexArrayName.get(0)); 206 | 207 | // model matrix 208 | { 209 | long now = System.currentTimeMillis(); 210 | float diff = (float) (now - start) / 1_000f; 211 | 212 | Mat4x4 model = new Mat4x4(); 213 | model 214 | .scale(0.5f) 215 | .rotate(diff, 0f, 0f, 1f) 216 | .to(matBuffer); 217 | 218 | gl.glUniformMatrix4fv(program.get("model"), 1, false, matBuffer); 219 | } 220 | 221 | gl.glDrawElements(GL_TRIANGLES, elementData.length, GL_UNSIGNED_SHORT, 0); 222 | 223 | gl.glUseProgram(0); 224 | gl.glBindVertexArray(0); 225 | 226 | checkError(gl, "display"); 227 | } 228 | 229 | @Override 230 | public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { 231 | 232 | GL3 gl = drawable.getGL().getGL3(); 233 | 234 | glm.ortho(-1f, 1f, -1f, 1f, 1f, -1f).to(matBuffer); 235 | 236 | gl.glBindBuffer(GL_UNIFORM_BUFFER, bufferName.get(Buffer.GLOBAL_MATRICES)); 237 | gl.glBufferSubData(GL_UNIFORM_BUFFER, 0, Mat4x4.SIZE, matBuffer); 238 | gl.glBindBuffer(GL_UNIFORM_BUFFER, 0); 239 | 240 | gl.glViewport(x, y, width, height); 241 | } 242 | 243 | @Override 244 | public void dispose(GLAutoDrawable drawable) { 245 | 246 | GL3 gl = drawable.getGL().getGL3(); 247 | 248 | gl.glDeleteProgram(program.name); 249 | gl.glDeleteVertexArrays(1, vertexArrayName); 250 | gl.glDeleteBuffers(Buffer.MAX, bufferName); 251 | 252 | destroyBuffers(vertexArrayName, bufferName, matBuffer, clearColor, clearDepth); 253 | } 254 | 255 | 256 | @Override 257 | public void keyPressed(KeyEvent e) { 258 | if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { 259 | new Thread(() -> { 260 | window.destroy(); 261 | }).start(); 262 | } 263 | } 264 | 265 | @Override 266 | public void keyReleased(KeyEvent e) { 267 | } 268 | } -------------------------------------------------------------------------------- /src/main/kotlin/gl4/helloTriangle.kt: -------------------------------------------------------------------------------- 1 | package gl4 2 | 3 | import com.jogamp.newt.event.KeyEvent 4 | import com.jogamp.newt.event.KeyListener 5 | import com.jogamp.newt.event.WindowAdapter 6 | import com.jogamp.newt.event.WindowEvent 7 | import com.jogamp.newt.opengl.GLWindow 8 | import com.jogamp.opengl.* 9 | import com.jogamp.opengl.GL2ES2.GL_DEBUG_SEVERITY_HIGH 10 | import com.jogamp.opengl.GL2ES2.GL_DEBUG_SEVERITY_MEDIUM 11 | import com.jogamp.opengl.GL2ES3.* 12 | import com.jogamp.opengl.GL4.GL_MAP_COHERENT_BIT 13 | import com.jogamp.opengl.GL4.GL_MAP_PERSISTENT_BIT 14 | import com.jogamp.opengl.util.Animator 15 | import framework.Semantic 16 | import glm.L 17 | import glm.SIZE 18 | import glm.f 19 | import glm.glm 20 | import glm.mat.Mat4 21 | import glm.vec._2.Vec2 22 | import glm.vec._3.Vec3 23 | import uno.buffer.* 24 | import uno.debug.GlDebugOutput 25 | import uno.glsl.Program 26 | import java.nio.ByteBuffer 27 | import kotlin.properties.Delegates 28 | 29 | /** 30 | * Created by elect on 06/03/17. 31 | */ 32 | 33 | fun main(args: Array) { 34 | HelloTriangleK().setup() 35 | } 36 | 37 | class HelloTriangleK : GLEventListener, KeyListener { 38 | 39 | var window by Delegates.notNull() 40 | val animator = Animator() 41 | 42 | val vertexData = floatArrayOf( 43 | -1f, -1f, 1f, 0f, 0f, 44 | +0f, +2f, 0f, 0f, 1f, 45 | +1f, -1f, 0f, 1f, 0f) 46 | 47 | val elementData = shortArrayOf(0, 2, 1) 48 | 49 | object Buffer { 50 | val VERTEX = 0 51 | val ELEMENT = 1 52 | val GLOBAL_MATRICES = 2 53 | val MODEL_MATRIX = 3 54 | val MAX = 4 55 | } 56 | 57 | val bufferName = intBufferBig(Buffer.MAX) 58 | val vertexArrayName = intBufferBig(1) 59 | 60 | val clearColor = floatBufferBig(4) 61 | val clearDepth = floatBufferBig(1) 62 | 63 | val matBuffer = floatBufferBig(16) 64 | 65 | var globalMatricesPointer by Delegates.notNull() 66 | var modelMatrixPointer by Delegates.notNull() 67 | 68 | // https://jogamp.org/bugzilla/show_bug.cgi?id=1287 69 | val bug1287 = true 70 | 71 | var program by Delegates.notNull() 72 | 73 | var start = 0L 74 | 75 | 76 | fun setup() { 77 | 78 | val glProfile = GLProfile.get(GLProfile.GL3) 79 | val glCapabilities = GLCapabilities(glProfile) 80 | 81 | window = GLWindow.create(glCapabilities) 82 | 83 | window.title = "Hello Triangle (enhanced)" 84 | window.setSize(1024, 768) 85 | 86 | window.contextCreationFlags = GLContext.CTX_OPTION_DEBUG 87 | window.isVisible = true 88 | 89 | window.addGLEventListener(this) 90 | window.addKeyListener(this) 91 | 92 | animator.add(window) 93 | animator.start() 94 | 95 | window.addWindowListener(object : WindowAdapter() { 96 | override fun windowDestroyed(e: WindowEvent?) { 97 | animator.stop(); System.exit(1); } 98 | }) 99 | } 100 | 101 | 102 | override fun init(drawable: GLAutoDrawable) { 103 | 104 | val gl = drawable.gl.gL4 105 | 106 | initDebug(gl) 107 | 108 | initBuffers(gl) 109 | 110 | initVertexArray(gl) 111 | 112 | program = Program(gl, this::class.java, "shaders/gl4", "hello-triangle.vert", "hello-triangle.frag") 113 | 114 | gl.glEnable(GL_DEPTH_TEST) 115 | 116 | start = System.currentTimeMillis() 117 | } 118 | 119 | fun initDebug(gl: GL4) = with(gl) { 120 | 121 | window.context.addGLDebugListener(GlDebugOutput()) 122 | 123 | // Turn off all the debug 124 | glDebugMessageControl( 125 | GL_DONT_CARE, // source 126 | GL_DONT_CARE, // type 127 | GL_DONT_CARE, // severity 128 | 0, null, // id 129 | false)// count 130 | // enabled 131 | // Turn on all OpenGL Errors, shader compilation/linking errors, or highly-dangerous undefined behavior 132 | glDebugMessageControl( 133 | GL_DONT_CARE, 134 | GL_DONT_CARE, 135 | GL_DEBUG_SEVERITY_HIGH, 136 | 0, null, 137 | true) 138 | // Turn on all major performance warnings, shader compilation/linking warnings or the use of deprecated functions 139 | glDebugMessageControl( 140 | GL_DONT_CARE, 141 | GL_DONT_CARE, 142 | GL_DEBUG_SEVERITY_MEDIUM, 143 | 0, null, 144 | true) 145 | } 146 | 147 | fun initBuffers(gl: GL4) = with(gl) { 148 | 149 | val vertexBuffer = vertexData.toFloatBuffer() 150 | val elementBuffer = elementData.toShortBuffer() 151 | 152 | glCreateBuffers(Buffer.MAX, bufferName) 153 | 154 | if (!bug1287) { 155 | 156 | glNamedBufferStorage(bufferName[Buffer.VERTEX], vertexBuffer.SIZE.L, vertexBuffer, GL_STATIC_DRAW) 157 | glNamedBufferStorage(bufferName[Buffer.ELEMENT], elementBuffer.SIZE.L, elementBuffer, GL_STATIC_DRAW) 158 | 159 | glNamedBufferStorage(bufferName[Buffer.GLOBAL_MATRICES], Mat4.SIZE.L * 2, null, GL_MAP_WRITE_BIT) 160 | glNamedBufferStorage(bufferName[Buffer.MODEL_MATRIX], Mat4.SIZE.L, null, GL_MAP_WRITE_BIT) 161 | 162 | } else { 163 | 164 | glBindBuffer(GL_ARRAY_BUFFER, bufferName[Buffer.VERTEX]) 165 | glBufferStorage(GL_ARRAY_BUFFER, vertexBuffer.SIZE.L, vertexBuffer, 0) 166 | glBindBuffer(GL_ARRAY_BUFFER, 0) 167 | 168 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferName[Buffer.ELEMENT]) 169 | glBufferStorage(GL_ELEMENT_ARRAY_BUFFER, elementBuffer.SIZE.L, elementBuffer, 0) 170 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) 171 | 172 | 173 | val uniformBufferOffset = intBufferBig(1) 174 | glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, uniformBufferOffset) 175 | val globalBlockSize = glm.max(Mat4.SIZE * 2, uniformBufferOffset[0]) 176 | val modelBlockSize = glm.max(Mat4.SIZE, uniformBufferOffset[0]) 177 | 178 | glBindBuffer(GL_UNIFORM_BUFFER, bufferName[Buffer.GLOBAL_MATRICES]) 179 | glBufferStorage(GL_UNIFORM_BUFFER, globalBlockSize.L, null, GL_MAP_WRITE_BIT or GL_MAP_PERSISTENT_BIT or GL_MAP_COHERENT_BIT) 180 | glBindBuffer(GL_UNIFORM_BUFFER, 0) 181 | 182 | glBindBuffer(GL_UNIFORM_BUFFER, bufferName[Buffer.MODEL_MATRIX]) 183 | glBufferStorage(GL_UNIFORM_BUFFER, modelBlockSize.L, null, GL_MAP_WRITE_BIT or GL_MAP_PERSISTENT_BIT or GL_MAP_COHERENT_BIT) 184 | glBindBuffer(GL_UNIFORM_BUFFER, 0) 185 | 186 | uniformBufferOffset.destroy() 187 | } 188 | 189 | destroyBuffers(vertexBuffer, elementBuffer) 190 | 191 | 192 | // map the transform buffers and keep them mapped 193 | globalMatricesPointer = glMapNamedBufferRange( 194 | bufferName[Buffer.GLOBAL_MATRICES], // buffer 195 | 0, // offset 196 | Mat4.SIZE.L * 2, // size 197 | GL_MAP_WRITE_BIT or GL_MAP_PERSISTENT_BIT or GL_MAP_COHERENT_BIT or GL_MAP_INVALIDATE_BUFFER_BIT) // flags 198 | 199 | modelMatrixPointer = glMapNamedBufferRange( 200 | bufferName[Buffer.MODEL_MATRIX], 201 | 0, 202 | Mat4.SIZE.L, 203 | GL_MAP_WRITE_BIT or GL_MAP_PERSISTENT_BIT or GL_MAP_COHERENT_BIT or GL_MAP_INVALIDATE_BUFFER_BIT) 204 | } 205 | 206 | fun initVertexArray(gl: GL4) = with(gl) { 207 | 208 | glCreateVertexArrays(1, vertexArrayName) 209 | 210 | glVertexArrayAttribBinding(vertexArrayName[0], Semantic.Attr.POSITION, Semantic.Stream.A) 211 | glVertexArrayAttribBinding(vertexArrayName[0], Semantic.Attr.COLOR, Semantic.Stream.A) 212 | 213 | glVertexArrayAttribFormat(vertexArrayName[0], Semantic.Attr.POSITION, Vec2.length, GL_FLOAT, false, 0) 214 | glVertexArrayAttribFormat(vertexArrayName[0], Semantic.Attr.COLOR, Vec3.length, GL_FLOAT, false, Vec2.SIZE) 215 | 216 | glEnableVertexArrayAttrib(vertexArrayName[0], Semantic.Attr.POSITION) 217 | glEnableVertexArrayAttrib(vertexArrayName[0], Semantic.Attr.COLOR) 218 | 219 | glVertexArrayElementBuffer(vertexArrayName[0], bufferName[Buffer.ELEMENT]) 220 | glVertexArrayVertexBuffer(vertexArrayName[0], Semantic.Stream.A, bufferName[Buffer.VERTEX], 0, Vec2.SIZE + Vec3.SIZE) 221 | } 222 | 223 | override fun display(drawable: GLAutoDrawable) = with(drawable.gl.gL4) { 224 | 225 | // update view matrix 226 | run { 227 | val view = Mat4() 228 | view.to(globalMatricesPointer, Mat4.SIZE) 229 | } 230 | 231 | 232 | glClearBufferfv(GL_COLOR, 0, clearColor.put(1f, .5f, 0f, 1f)) 233 | glClearBufferfv(GL_DEPTH, 0, clearDepth.put(0, 1f)) 234 | 235 | run { 236 | // update model matrix based on time 237 | val now = System.currentTimeMillis() 238 | val diff = (now - start).f / 1_000f 239 | 240 | // Here we build the matrix that will multiply our original vertex positions. We scale, half and rotate it. 241 | val model = Mat4() 242 | model 243 | .scale_(0.5f) 244 | .rotate_(diff, 0f, 0f, 1f) 245 | .to(modelMatrixPointer) 246 | } 247 | 248 | glUseProgram(program.name) 249 | glBindVertexArray(vertexArrayName[0]) 250 | 251 | glBindBufferBase( 252 | GL_UNIFORM_BUFFER, // target 253 | Semantic.Uniform.TRANSFORM0, // index 254 | bufferName[Buffer.GLOBAL_MATRICES]) // buffer 255 | 256 | glBindBufferBase( 257 | GL_UNIFORM_BUFFER, 258 | Semantic.Uniform.TRANSFORM1, 259 | bufferName[Buffer.MODEL_MATRIX]) 260 | 261 | glDrawElements( 262 | GL_TRIANGLES, // primitive mode 263 | elementData.size, // element count 264 | GL_UNSIGNED_SHORT, // element type 265 | 0) // element offset 266 | 267 | glUseProgram(0) 268 | glBindVertexArray(0) 269 | } 270 | 271 | override fun reshape(drawable: GLAutoDrawable, x: Int, y: Int, width: Int, height: Int) = with(drawable.gl.gL4) { 272 | 273 | glm.ortho(-1f, 1f, -1f, 1f, 1f, -1f) to globalMatricesPointer 274 | 275 | glViewport(x, y, width, height) 276 | } 277 | 278 | override fun dispose(drawable: GLAutoDrawable) = with(drawable.gl.gL4) { 279 | 280 | glUnmapNamedBuffer(bufferName[Buffer.GLOBAL_MATRICES]) 281 | glUnmapNamedBuffer(bufferName[Buffer.MODEL_MATRIX]) 282 | 283 | glDeleteProgram(program.name) 284 | glDeleteVertexArrays(1, vertexArrayName) 285 | glDeleteBuffers(Buffer.MAX, bufferName) 286 | 287 | destroyBuffers(vertexArrayName, bufferName, clearColor, clearDepth) 288 | } 289 | 290 | override fun keyPressed(e: KeyEvent) { 291 | if (e.keyCode == KeyEvent.VK_ESCAPE) { 292 | /* Note: calling System.exit() synchronously inside the draw, reshape or init callbacks can lead to 293 | deadlocks on certain platforms (in particular, X11) because the JAWT's locking routines cause a global 294 | AWT lock to be grabbed. Run the exit routine in another thread. */ 295 | Thread { window.destroy() }.start() 296 | } 297 | } 298 | 299 | override fun keyReleased(e: KeyEvent) {} 300 | } -------------------------------------------------------------------------------- /src/main/java/gl4/HelloTriangle.java: -------------------------------------------------------------------------------- 1 | 2 | package gl4; 3 | 4 | import com.jogamp.newt.event.KeyEvent; 5 | import com.jogamp.newt.event.KeyListener; 6 | import com.jogamp.newt.event.WindowAdapter; 7 | import com.jogamp.newt.event.WindowEvent; 8 | import com.jogamp.newt.opengl.GLWindow; 9 | import com.jogamp.opengl.*; 10 | import com.jogamp.opengl.util.Animator; 11 | import com.jogamp.opengl.util.GLBuffers; 12 | import framework.Semantic; 13 | import glm.mat.Mat4x4; 14 | import glm.vec._2.Vec2; 15 | import glm.vec._3.Vec3; 16 | import uno.debug.GlDebugOutput; 17 | import uno.glsl.Program; 18 | 19 | import java.nio.ByteBuffer; 20 | import java.nio.FloatBuffer; 21 | import java.nio.IntBuffer; 22 | import java.nio.ShortBuffer; 23 | 24 | import static com.jogamp.opengl.GL3.*; 25 | import static com.jogamp.opengl.GL4.GL_MAP_COHERENT_BIT; 26 | import static com.jogamp.opengl.GL4.GL_MAP_PERSISTENT_BIT; 27 | import static glm.GlmKt.glm; 28 | import static uno.buffer.UtilKt.destroyBuffer; 29 | import static uno.buffer.UtilKt.destroyBuffers; 30 | 31 | /** 32 | * @author gbarbieri 33 | */ 34 | public class HelloTriangle implements GLEventListener, KeyListener { 35 | 36 | private static GLWindow window; 37 | private static Animator animator; 38 | 39 | public static void main(String[] args) { 40 | new HelloTriangle().setup(); 41 | } 42 | 43 | private float[] vertexData = { 44 | -1, -1, 1, 0, 0, 45 | +0, +2, 0, 0, 1, 46 | +1, -1, 0, 1, 0}; 47 | 48 | private short[] elementData = {0, 2, 1}; 49 | 50 | private interface Buffer { 51 | 52 | int VERTEX = 0; 53 | int ELEMENT = 1; 54 | int GLOBAL_MATRICES = 2; 55 | int MODEL_MATRIX = 3; 56 | int MAX = 4; 57 | } 58 | 59 | private IntBuffer bufferName = GLBuffers.newDirectIntBuffer(Buffer.MAX); 60 | private IntBuffer vertexArrayName = GLBuffers.newDirectIntBuffer(1); 61 | 62 | private FloatBuffer clearColor = GLBuffers.newDirectFloatBuffer(4); 63 | private FloatBuffer clearDepth = GLBuffers.newDirectFloatBuffer(1); 64 | 65 | private FloatBuffer matBuffer = GLBuffers.newDirectFloatBuffer(16); 66 | 67 | private ByteBuffer globalMatricesPointer, modelMatrixPointer; 68 | // https://jogamp.org/bugzilla/show_bug.cgi?id=1287 69 | private boolean bug1287 = true; 70 | 71 | private Program program; 72 | 73 | private long start; 74 | 75 | 76 | private void setup() { 77 | 78 | GLProfile glProfile = GLProfile.get(GLProfile.GL3); 79 | GLCapabilities glCapabilities = new GLCapabilities(glProfile); 80 | 81 | window = GLWindow.create(glCapabilities); 82 | 83 | window.setTitle("Hello Triangle (enhanced)"); 84 | window.setSize(1024, 768); 85 | 86 | window.addGLEventListener(this); 87 | window.addKeyListener(this); 88 | 89 | window.setContextCreationFlags(GLContext.CTX_OPTION_DEBUG); 90 | window.setVisible(true); 91 | 92 | animator = new Animator(window); 93 | animator.start(); 94 | 95 | window.addWindowListener(new WindowAdapter() { 96 | @Override 97 | public void windowDestroyed(WindowEvent e) { 98 | animator.stop(); 99 | System.exit(1); 100 | } 101 | }); 102 | } 103 | 104 | 105 | @Override 106 | public void init(GLAutoDrawable drawable) { 107 | 108 | GL4 gl = drawable.getGL().getGL4(); 109 | 110 | initDebug(gl); 111 | 112 | initBuffers(gl); 113 | 114 | initVertexArray(gl); 115 | 116 | program = new Program(gl, getClass(), "shaders/gl4", "hello-triangle.vert", "hello-triangle.frag"); 117 | 118 | gl.glEnable(GL_DEPTH_TEST); 119 | 120 | start = System.currentTimeMillis(); 121 | } 122 | 123 | private void initDebug(GL4 gl) { 124 | 125 | window.getContext().addGLDebugListener(new GlDebugOutput()); 126 | 127 | gl.glDebugMessageControl( 128 | GL_DONT_CARE, 129 | GL_DONT_CARE, 130 | GL_DONT_CARE, 131 | 0, 132 | null, 133 | false); 134 | 135 | gl.glDebugMessageControl( 136 | GL_DONT_CARE, 137 | GL_DONT_CARE, 138 | GL_DEBUG_SEVERITY_HIGH, 139 | 0, 140 | null, 141 | true); 142 | 143 | gl.glDebugMessageControl( 144 | GL_DONT_CARE, 145 | GL_DONT_CARE, 146 | GL_DEBUG_SEVERITY_MEDIUM, 147 | 0, 148 | null, 149 | true); 150 | } 151 | 152 | private void initBuffers(GL4 gl) { 153 | 154 | FloatBuffer vertexBuffer = GLBuffers.newDirectFloatBuffer(vertexData); 155 | ShortBuffer elementBuffer = GLBuffers.newDirectShortBuffer(elementData); 156 | 157 | gl.glCreateBuffers(Buffer.MAX, bufferName); 158 | 159 | if (!bug1287) { 160 | 161 | gl.glNamedBufferStorage(bufferName.get(Buffer.VERTEX), vertexBuffer.capacity() * Float.BYTES, vertexBuffer, 162 | GL_STATIC_DRAW); 163 | gl.glNamedBufferStorage(bufferName.get(Buffer.ELEMENT), elementBuffer.capacity() * Short.BYTES, 164 | elementBuffer, GL_STATIC_DRAW); 165 | 166 | gl.glNamedBufferStorage(bufferName.get(Buffer.GLOBAL_MATRICES), Mat4x4.SIZE * 2, null, GL_MAP_WRITE_BIT); 167 | gl.glNamedBufferStorage(bufferName.get(Buffer.MODEL_MATRIX), Mat4x4.SIZE, null, GL_MAP_WRITE_BIT); 168 | 169 | } else { 170 | 171 | gl.glBindBuffer(GL_ARRAY_BUFFER, bufferName.get(Buffer.VERTEX)); 172 | gl.glBufferStorage(GL_ARRAY_BUFFER, vertexBuffer.capacity() * Float.BYTES, vertexBuffer, 0); 173 | gl.glBindBuffer(GL_ARRAY_BUFFER, 0); 174 | 175 | gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferName.get(Buffer.ELEMENT)); 176 | gl.glBufferStorage(GL_ELEMENT_ARRAY_BUFFER, elementBuffer.capacity() * Short.BYTES, elementBuffer, 0); 177 | gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 178 | 179 | 180 | IntBuffer uniformBufferOffset = GLBuffers.newDirectIntBuffer(1); 181 | gl.glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, uniformBufferOffset); 182 | int globalBlockSize = glm.max(Mat4x4.SIZE * 2, uniformBufferOffset.get(0)); 183 | int modelBlockSize = glm.max(Mat4x4.SIZE, uniformBufferOffset.get(0)); 184 | 185 | gl.glBindBuffer(GL_UNIFORM_BUFFER, bufferName.get(Buffer.GLOBAL_MATRICES)); 186 | gl.glBufferStorage(GL_UNIFORM_BUFFER, globalBlockSize, null, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); 187 | gl.glBindBuffer(GL_UNIFORM_BUFFER, 0); 188 | 189 | gl.glBindBuffer(GL_UNIFORM_BUFFER, bufferName.get(Buffer.MODEL_MATRIX)); 190 | gl.glBufferStorage(GL_UNIFORM_BUFFER, modelBlockSize, null, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); 191 | gl.glBindBuffer(GL_UNIFORM_BUFFER, 0); 192 | 193 | destroyBuffer(uniformBufferOffset); 194 | } 195 | 196 | destroyBuffers(vertexBuffer, elementBuffer); 197 | 198 | 199 | // map the transform buffers and keep them mapped 200 | globalMatricesPointer = gl.glMapNamedBufferRange( 201 | bufferName.get(Buffer.GLOBAL_MATRICES), 202 | 0, 203 | Mat4x4.SIZE * 2, 204 | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); // flags 205 | 206 | modelMatrixPointer = gl.glMapNamedBufferRange( 207 | bufferName.get(Buffer.MODEL_MATRIX), 208 | 0, 209 | Mat4x4.SIZE, 210 | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); 211 | } 212 | 213 | private void initVertexArray(GL4 gl) { 214 | 215 | gl.glCreateVertexArrays(1, vertexArrayName); 216 | 217 | gl.glVertexArrayAttribBinding(vertexArrayName.get(0), Semantic.Attr.POSITION, Semantic.Stream.A); 218 | gl.glVertexArrayAttribBinding(vertexArrayName.get(0), Semantic.Attr.COLOR, Semantic.Stream.A); 219 | 220 | gl.glVertexArrayAttribFormat(vertexArrayName.get(0), Semantic.Attr.POSITION, Vec2.length, GL_FLOAT, false, 0); 221 | gl.glVertexArrayAttribFormat(vertexArrayName.get(0), Semantic.Attr.COLOR, Vec3.length, GL_FLOAT, false, Vec2.SIZE); 222 | 223 | gl.glEnableVertexArrayAttrib(vertexArrayName.get(0), Semantic.Attr.POSITION); 224 | gl.glEnableVertexArrayAttrib(vertexArrayName.get(0), Semantic.Attr.COLOR); 225 | 226 | gl.glVertexArrayElementBuffer(vertexArrayName.get(0), bufferName.get(Buffer.ELEMENT)); 227 | gl.glVertexArrayVertexBuffer(vertexArrayName.get(0), Semantic.Stream.A, bufferName.get(Buffer.VERTEX), 0, 228 | Vec2.SIZE + Vec3.SIZE); 229 | } 230 | 231 | @Override 232 | public void display(GLAutoDrawable drawable) { 233 | 234 | GL4 gl = drawable.getGL().getGL4(); 235 | 236 | 237 | // view matrix 238 | { 239 | Mat4x4 view = new Mat4x4(); 240 | view.to(globalMatricesPointer, Mat4x4.SIZE); 241 | } 242 | 243 | 244 | gl.glClearBufferfv(GL_COLOR, 0, clearColor.put(0, 1f).put(1, .5f).put(2, 0f).put(3, 1f)); 245 | gl.glClearBufferfv(GL_DEPTH, 0, clearDepth.put(0, 1f)); 246 | 247 | // model matrix 248 | { 249 | long now = System.currentTimeMillis(); 250 | float diff = (float) (now - start) / 1_000; 251 | 252 | Mat4x4 model = new Mat4x4(); 253 | model 254 | .scale_(0.5f) 255 | .rotate_(diff, 0f, 0f, 1f) 256 | .to(modelMatrixPointer); 257 | } 258 | 259 | gl.glUseProgram(program.name); 260 | gl.glBindVertexArray(vertexArrayName.get(0)); 261 | 262 | gl.glBindBufferBase( 263 | GL_UNIFORM_BUFFER, 264 | Semantic.Uniform.TRANSFORM0, 265 | bufferName.get(Buffer.GLOBAL_MATRICES)); 266 | 267 | gl.glBindBufferBase( 268 | GL_UNIFORM_BUFFER, 269 | Semantic.Uniform.TRANSFORM1, 270 | bufferName.get(Buffer.MODEL_MATRIX)); 271 | 272 | gl.glDrawElements( 273 | GL_TRIANGLES, 274 | elementData.length, 275 | GL_UNSIGNED_SHORT, 276 | 0); 277 | 278 | gl.glUseProgram(0); 279 | gl.glBindVertexArray(0); 280 | } 281 | 282 | @Override 283 | public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { 284 | 285 | GL4 gl = drawable.getGL().getGL4(); 286 | 287 | // ortho matrix 288 | glm.ortho(-1f, 1f, -1f, 1f, 1f, -1f).to(globalMatricesPointer); 289 | 290 | gl.glViewport(x, y, width, height); 291 | } 292 | 293 | @Override 294 | public void dispose(GLAutoDrawable drawable) { 295 | 296 | GL4 gl = drawable.getGL().getGL4(); 297 | 298 | gl.glUnmapNamedBuffer(bufferName.get(Buffer.GLOBAL_MATRICES)); 299 | gl.glUnmapNamedBuffer(bufferName.get(Buffer.MODEL_MATRIX)); 300 | 301 | gl.glDeleteProgram(program.name); 302 | gl.glDeleteVertexArrays(1, vertexArrayName); 303 | gl.glDeleteBuffers(Buffer.MAX, bufferName); 304 | 305 | destroyBuffers(vertexArrayName, bufferName, clearColor, clearDepth); 306 | } 307 | 308 | @Override 309 | public void keyPressed(KeyEvent e) { 310 | if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { 311 | new Thread(() -> { 312 | window.destroy(); 313 | }).start(); 314 | } 315 | } 316 | 317 | @Override 318 | public void keyReleased(KeyEvent e) { 319 | } 320 | } -------------------------------------------------------------------------------- /src/main/java/gl3/HelloTriangleSimple.java: -------------------------------------------------------------------------------- 1 | 2 | package gl3; 3 | 4 | import com.jogamp.newt.event.KeyEvent; 5 | import com.jogamp.newt.event.KeyListener; 6 | import com.jogamp.newt.event.WindowAdapter; 7 | import com.jogamp.newt.event.WindowEvent; 8 | import com.jogamp.newt.opengl.GLWindow; 9 | import com.jogamp.opengl.*; 10 | import com.jogamp.opengl.math.FloatUtil; 11 | import com.jogamp.opengl.util.Animator; 12 | import com.jogamp.opengl.util.GLBuffers; 13 | import com.jogamp.opengl.util.glsl.ShaderCode; 14 | import com.jogamp.opengl.util.glsl.ShaderProgram; 15 | import framework.Semantic; 16 | 17 | import java.nio.FloatBuffer; 18 | import java.nio.IntBuffer; 19 | import java.nio.ShortBuffer; 20 | 21 | import static com.jogamp.opengl.GL.GL_ELEMENT_ARRAY_BUFFER; 22 | import static com.jogamp.opengl.GL.GL_STATIC_DRAW; 23 | import static com.jogamp.opengl.GL.GL_TRIANGLES; 24 | import static com.jogamp.opengl.GL.GL_UNSIGNED_SHORT; 25 | import static com.jogamp.opengl.GL3.GL_ARRAY_BUFFER; 26 | import static com.jogamp.opengl.GL3.*; 27 | import static com.jogamp.opengl.GL3.GL_DEPTH_TEST; 28 | import static com.jogamp.opengl.GL3.GL_FLOAT; 29 | import static com.jogamp.opengl.GL3.GL_INVALID_ENUM; 30 | import static com.jogamp.opengl.GL3.GL_INVALID_FRAMEBUFFER_OPERATION; 31 | import static com.jogamp.opengl.GL3.GL_INVALID_OPERATION; 32 | import static com.jogamp.opengl.GL3.GL_INVALID_VALUE; 33 | import static com.jogamp.opengl.GL3.GL_NO_ERROR; 34 | import static com.jogamp.opengl.GL3.GL_OUT_OF_MEMORY; 35 | 36 | /** 37 | * @author gbarbieri 38 | */ 39 | public class HelloTriangleSimple implements GLEventListener, KeyListener { 40 | 41 | private static GLWindow window; 42 | private static Animator animator; 43 | 44 | public static void main(String[] args) { 45 | new HelloTriangleSimple().setup(); 46 | } 47 | 48 | private float[] vertexData = { 49 | -1, -1, 1, 0, 0, 50 | +0, +2, 0, 0, 1, 51 | +1, -1, 0, 1, 0}; 52 | 53 | private short[] elementData = {0, 2, 1}; 54 | 55 | private interface Buffer { 56 | 57 | int VERTEX = 0; 58 | int ELEMENT = 1; 59 | int GLOBAL_MATRICES = 2; 60 | int MAX = 3; 61 | } 62 | 63 | private IntBuffer bufferName = GLBuffers.newDirectIntBuffer(Buffer.MAX); 64 | private IntBuffer vertexArrayName = GLBuffers.newDirectIntBuffer(1); 65 | 66 | private FloatBuffer clearColor = GLBuffers.newDirectFloatBuffer(4); 67 | private FloatBuffer clearDepth = GLBuffers.newDirectFloatBuffer(1); 68 | 69 | private FloatBuffer matBuffer = GLBuffers.newDirectFloatBuffer(16); 70 | 71 | private Program program; 72 | 73 | private long start; 74 | 75 | private void setup() { 76 | 77 | GLProfile glProfile = GLProfile.get(GLProfile.GL3); 78 | GLCapabilities glCapabilities = new GLCapabilities(glProfile); 79 | 80 | window = GLWindow.create(glCapabilities); 81 | 82 | window.setTitle("Hello Triangle (simple)"); 83 | window.setSize(1024, 768); 84 | 85 | window.setVisible(true); 86 | 87 | window.addGLEventListener(this); 88 | window.addKeyListener(this); 89 | 90 | animator = new Animator(window); 91 | animator.start(); 92 | 93 | window.addWindowListener(new WindowAdapter() { 94 | @Override 95 | public void windowDestroyed(WindowEvent e) { 96 | animator.stop(); 97 | System.exit(1); 98 | } 99 | }); 100 | 101 | } 102 | 103 | @Override 104 | public void init(GLAutoDrawable drawable) { 105 | 106 | GL3 gl = drawable.getGL().getGL3(); 107 | 108 | initBuffers(gl); 109 | 110 | initVertexArray(gl); 111 | 112 | initProgram(gl); 113 | 114 | gl.glEnable(GL_DEPTH_TEST); 115 | 116 | start = System.currentTimeMillis(); 117 | } 118 | 119 | private void initBuffers(GL3 gl) { 120 | 121 | FloatBuffer vertexBuffer = GLBuffers.newDirectFloatBuffer(vertexData); 122 | ShortBuffer elementBuffer = GLBuffers.newDirectShortBuffer(elementData); 123 | 124 | gl.glGenBuffers(Buffer.MAX, bufferName); 125 | 126 | gl.glBindBuffer(GL_ARRAY_BUFFER, bufferName.get(Buffer.VERTEX)); 127 | gl.glBufferData(GL_ARRAY_BUFFER, vertexBuffer.capacity() * Float.BYTES, vertexBuffer, GL_STATIC_DRAW); 128 | gl.glBindBuffer(GL_ARRAY_BUFFER, 0); 129 | 130 | gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferName.get(Buffer.ELEMENT)); 131 | gl.glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementBuffer.capacity() * Short.BYTES, elementBuffer, GL_STATIC_DRAW); 132 | gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 133 | 134 | 135 | gl.glBindBuffer(GL_UNIFORM_BUFFER, bufferName.get(Buffer.GLOBAL_MATRICES)); 136 | gl.glBufferData(GL_UNIFORM_BUFFER, 16 * Float.BYTES * 2, null, GL_STREAM_DRAW); 137 | gl.glBindBuffer(GL_UNIFORM_BUFFER, 0); 138 | 139 | gl.glBindBufferBase(GL_UNIFORM_BUFFER, Semantic.Uniform.GLOBAL_MATRICES, bufferName.get(Buffer.GLOBAL_MATRICES)); 140 | 141 | checkError(gl, "initBuffers"); 142 | } 143 | 144 | private void initVertexArray(GL3 gl) { 145 | 146 | gl.glGenVertexArrays(1, vertexArrayName); 147 | gl.glBindVertexArray(vertexArrayName.get(0)); 148 | { 149 | gl.glBindBuffer(GL_ARRAY_BUFFER, bufferName.get(Buffer.VERTEX)); 150 | { 151 | int stride = (2 + 3) * Float.BYTES; 152 | int offset = 0; 153 | 154 | gl.glEnableVertexAttribArray(Semantic.Attr.POSITION); 155 | gl.glVertexAttribPointer(Semantic.Attr.POSITION, 2, GL_FLOAT, false, stride, offset); 156 | 157 | offset = 2 * Float.BYTES; 158 | gl.glEnableVertexAttribArray(Semantic.Attr.COLOR); 159 | gl.glVertexAttribPointer(Semantic.Attr.COLOR, 3, GL_FLOAT, false, stride, offset); 160 | } 161 | gl.glBindBuffer(GL_ARRAY_BUFFER, 0); 162 | 163 | gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferName.get(Buffer.ELEMENT)); 164 | } 165 | gl.glBindVertexArray(0); 166 | 167 | checkError(gl, "initVao"); 168 | } 169 | 170 | private void initProgram(GL3 gl) { 171 | 172 | program = new Program(gl, getClass(), "shaders/gl3", "hello-triangle", "hello-triangle"); 173 | 174 | checkError(gl, "initProgram"); 175 | } 176 | 177 | @Override 178 | public void display(GLAutoDrawable drawable) { 179 | 180 | GL3 gl = drawable.getGL().getGL3(); 181 | 182 | // view matrix 183 | { 184 | float[] view = new float[16]; 185 | FloatUtil.makeIdentity(view); 186 | 187 | for (int i = 0; i < 16; i++) { 188 | matBuffer.put(i, view[i]); 189 | } 190 | gl.glBindBuffer(GL_UNIFORM_BUFFER, bufferName.get(Buffer.GLOBAL_MATRICES)); 191 | gl.glBufferSubData(GL_UNIFORM_BUFFER, 16 * Float.BYTES, 16 * Float.BYTES, matBuffer); 192 | gl.glBindBuffer(GL_UNIFORM_BUFFER, 0); 193 | } 194 | 195 | gl.glClearBufferfv(GL_COLOR, 0, clearColor.put(0, 0f).put(1, .33f).put(2, 0.66f).put(3, 1f)); 196 | gl.glClearBufferfv(GL_DEPTH, 0, clearDepth.put(0, 1f)); 197 | 198 | gl.glUseProgram(program.name); 199 | gl.glBindVertexArray(vertexArrayName.get(0)); 200 | 201 | // model matrix 202 | { 203 | long now = System.currentTimeMillis(); 204 | float diff = (float) (now - start) / 1_000f; 205 | 206 | float[] scale = FloatUtil.makeScale(new float[16], true, 0.5f, 0.5f, 0.5f); 207 | float[] zRotation = FloatUtil.makeRotationEuler(new float[16], 0, 0, 0, diff); 208 | float[] modelToWorldMat = FloatUtil.multMatrix(scale, zRotation); 209 | 210 | for (int i = 0; i < 16; i++) { 211 | matBuffer.put(i, modelToWorldMat[i]); 212 | } 213 | gl.glUniformMatrix4fv(program.modelToWorldMatUL, 1, false, matBuffer); 214 | } 215 | 216 | gl.glDrawElements(GL_TRIANGLES, elementData.length, GL_UNSIGNED_SHORT, 0); 217 | 218 | gl.glUseProgram(0); 219 | gl.glBindVertexArray(0); 220 | 221 | checkError(gl, "display"); 222 | } 223 | 224 | @Override 225 | public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { 226 | 227 | GL3 gl = drawable.getGL().getGL3(); 228 | 229 | float[] ortho = new float[16]; 230 | FloatUtil.makeOrtho(ortho, 0, false, -1, 1, -1, 1, 1, -1); 231 | for (int i = 0; i < 16; i++) { 232 | matBuffer.put(i, ortho[i]); 233 | } 234 | gl.glBindBuffer(GL_UNIFORM_BUFFER, bufferName.get(Buffer.GLOBAL_MATRICES)); 235 | gl.glBufferSubData(GL_UNIFORM_BUFFER, 0, 16 * Float.BYTES, matBuffer); 236 | gl.glBindBuffer(GL_UNIFORM_BUFFER, 0); 237 | 238 | gl.glViewport(x, y, width, height); 239 | } 240 | 241 | @Override 242 | public void dispose(GLAutoDrawable drawable) { 243 | 244 | GL3 gl = drawable.getGL().getGL3(); 245 | 246 | gl.glDeleteProgram(program.name); 247 | gl.glDeleteVertexArrays(1, vertexArrayName); 248 | gl.glDeleteBuffers(Buffer.MAX, bufferName); 249 | } 250 | 251 | 252 | @Override 253 | public void keyPressed(KeyEvent e) { 254 | if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { 255 | new Thread(() -> { 256 | window.destroy(); 257 | }).start(); 258 | } 259 | } 260 | 261 | @Override 262 | public void keyReleased(KeyEvent e) { 263 | } 264 | 265 | private class Program { 266 | 267 | int name, modelToWorldMatUL; 268 | 269 | Program(GL3 gl, Class context, String root, String vertex, String fragment) { 270 | 271 | ShaderCode vertShader = ShaderCode.create(gl, GL_VERTEX_SHADER, this.getClass(), root, null, vertex, 272 | "vert", null, true); 273 | ShaderCode fragShader = ShaderCode.create(gl, GL_FRAGMENT_SHADER, this.getClass(), root, null, fragment, 274 | "frag", null, true); 275 | 276 | ShaderProgram shaderProgram = new ShaderProgram(); 277 | 278 | shaderProgram.add(vertShader); 279 | shaderProgram.add(fragShader); 280 | 281 | shaderProgram.init(gl); 282 | 283 | name = shaderProgram.program(); 284 | 285 | shaderProgram.link(gl, System.err); 286 | 287 | 288 | modelToWorldMatUL = gl.glGetUniformLocation(name, "model"); 289 | 290 | if (modelToWorldMatUL == -1) { 291 | System.err.println("uniform 'model' not found!"); 292 | } 293 | 294 | 295 | int globalMatricesBI = gl.glGetUniformBlockIndex(name, "GlobalMatrices"); 296 | 297 | if (globalMatricesBI == -1) { 298 | System.err.println("block index 'GlobalMatrices' not found!"); 299 | } 300 | gl.glUniformBlockBinding(name, globalMatricesBI, Semantic.Uniform.GLOBAL_MATRICES); 301 | } 302 | } 303 | 304 | private void checkError(GL gl, String location) { 305 | 306 | int error = gl.glGetError(); 307 | if (error != GL_NO_ERROR) { 308 | String errorString; 309 | switch (error) { 310 | case GL_INVALID_ENUM: 311 | errorString = "GL_INVALID_ENUM"; 312 | break; 313 | case GL_INVALID_VALUE: 314 | errorString = "GL_INVALID_VALUE"; 315 | break; 316 | case GL_INVALID_OPERATION: 317 | errorString = "GL_INVALID_OPERATION"; 318 | break; 319 | case GL_INVALID_FRAMEBUFFER_OPERATION: 320 | errorString = "GL_INVALID_FRAMEBUFFER_OPERATION"; 321 | break; 322 | case GL_OUT_OF_MEMORY: 323 | errorString = "GL_OUT_OF_MEMORY"; 324 | break; 325 | default: 326 | errorString = "UNKNOWN"; 327 | break; 328 | } 329 | throw new Error("OpenGL Error(" + errorString + "): " + location); 330 | } 331 | } 332 | } 333 | -------------------------------------------------------------------------------- /src/main/java/gl3/HelloTexture.java: -------------------------------------------------------------------------------- 1 | 2 | package gl3; 3 | 4 | import com.jogamp.newt.event.KeyEvent; 5 | import com.jogamp.newt.event.KeyListener; 6 | import com.jogamp.newt.event.WindowAdapter; 7 | import com.jogamp.newt.event.WindowEvent; 8 | import com.jogamp.newt.opengl.GLWindow; 9 | import com.jogamp.opengl.*; 10 | import com.jogamp.opengl.util.Animator; 11 | import com.jogamp.opengl.util.GLBuffers; 12 | import com.jogamp.opengl.util.texture.TextureData; 13 | import com.jogamp.opengl.util.texture.TextureIO; 14 | import framework.Semantic; 15 | import glm.mat.Mat4x4; 16 | import glm.vec._2.Vec2; 17 | import uno.glsl.Program; 18 | 19 | import java.io.IOException; 20 | import java.net.URL; 21 | import java.nio.FloatBuffer; 22 | import java.nio.IntBuffer; 23 | import java.nio.ShortBuffer; 24 | import java.util.logging.Level; 25 | import java.util.logging.Logger; 26 | 27 | import static com.jogamp.opengl.GL.GL_ARRAY_BUFFER; 28 | import static com.jogamp.opengl.GL.GL_DEPTH_TEST; 29 | import static com.jogamp.opengl.GL.GL_ELEMENT_ARRAY_BUFFER; 30 | import static com.jogamp.opengl.GL.GL_FLOAT; 31 | import static com.jogamp.opengl.GL.GL_STATIC_DRAW; 32 | import static com.jogamp.opengl.GL.GL_TRIANGLES; 33 | import static com.jogamp.opengl.GL.GL_UNSIGNED_SHORT; 34 | import static com.jogamp.opengl.GL2ES2.GL_STREAM_DRAW; 35 | import static com.jogamp.opengl.GL2ES3.*; 36 | import static com.jogamp.opengl.GL2ES3.GL_CLAMP_TO_EDGE; 37 | import static com.jogamp.opengl.GL2ES3.GL_NEAREST; 38 | import static com.jogamp.opengl.GL2ES3.GL_ONE; 39 | import static com.jogamp.opengl.GL2ES3.GL_TEXTURE0; 40 | import static com.jogamp.opengl.GL2ES3.GL_TEXTURE_2D; 41 | import static com.jogamp.opengl.GL2ES3.GL_TEXTURE_MAG_FILTER; 42 | import static com.jogamp.opengl.GL2ES3.GL_TEXTURE_MIN_FILTER; 43 | import static com.jogamp.opengl.GL2ES3.GL_TEXTURE_WRAP_S; 44 | import static com.jogamp.opengl.GL2ES3.GL_TEXTURE_WRAP_T; 45 | import static com.jogamp.opengl.GL2GL3.GL_TEXTURE_SWIZZLE_RGBA; 46 | import static glm.GlmKt.glm; 47 | import static uno.buffer.UtilKt.destroyBuffer; 48 | import static uno.buffer.UtilKt.destroyBuffers; 49 | import static uno.gl.GlErrorKt.checkError; 50 | 51 | /** 52 | * @author gbarbieri 53 | */ 54 | public class HelloTexture implements GLEventListener, KeyListener { 55 | 56 | private static GLWindow window; 57 | private static Animator animator; 58 | 59 | public static void main(String[] args) { 60 | new HelloTextureK().setup(); 61 | } 62 | 63 | private float[] vertexData = { 64 | -1f, -1f, 0f, 0f, 65 | -1f, +1f, 0f, 1f, 66 | +1f, +1f, 1f, 1f, 67 | +1f, -1f, 1f, 0f}; 68 | 69 | private short[] elementData = { 70 | 0, 1, 3, 71 | 1, 2, 3}; 72 | 73 | private interface Buffer { 74 | 75 | int VERTEX = 0; 76 | int ELEMENT = 1; 77 | int GLOBAL_MATRICES = 2; 78 | int MAX = 3; 79 | } 80 | 81 | private IntBuffer bufferName = GLBuffers.newDirectIntBuffer(Buffer.MAX); 82 | private IntBuffer vertexArrayName = GLBuffers.newDirectIntBuffer(1); 83 | 84 | private IntBuffer textureName = GLBuffers.newDirectIntBuffer(1); 85 | private IntBuffer samplerName = GLBuffers.newDirectIntBuffer(1); 86 | 87 | private FloatBuffer clearColor = GLBuffers.newDirectFloatBuffer(4); 88 | private FloatBuffer clearDepth = GLBuffers.newDirectFloatBuffer(1); 89 | 90 | private FloatBuffer matBuffer = GLBuffers.newDirectFloatBuffer(16); 91 | 92 | private Program program; 93 | 94 | private long start; 95 | 96 | private void setup() { 97 | 98 | GLProfile glProfile = GLProfile.get(GLProfile.GL3); 99 | GLCapabilities glCapabilities = new GLCapabilities(glProfile); 100 | 101 | window = GLWindow.create(glCapabilities); 102 | 103 | window.setTitle("Hello Texture"); 104 | window.setSize(1024, 768); 105 | 106 | window.setVisible(true); 107 | 108 | window.addGLEventListener(this); 109 | window.addKeyListener(this); 110 | 111 | animator = new Animator(); 112 | animator.add(window); 113 | animator.start(); 114 | 115 | window.addWindowListener(new WindowAdapter() { 116 | @Override 117 | public void windowDestroyed(WindowEvent e) { 118 | animator.stop(); 119 | System.exit(1); 120 | } 121 | }); 122 | 123 | } 124 | 125 | @Override 126 | public void init(GLAutoDrawable drawable) { 127 | 128 | GL3 gl = drawable.getGL().getGL3(); 129 | 130 | initBuffers(gl); 131 | 132 | initVertexArray(gl); 133 | 134 | initTexture(gl); 135 | 136 | initSampler(gl); 137 | 138 | initProgram(gl); 139 | 140 | gl.glEnable(GL_DEPTH_TEST); 141 | 142 | start = System.currentTimeMillis(); 143 | } 144 | 145 | private void initBuffers(GL3 gl) { 146 | 147 | FloatBuffer vertexBuffer = GLBuffers.newDirectFloatBuffer(vertexData); 148 | ShortBuffer elementBuffer = GLBuffers.newDirectShortBuffer(elementData); 149 | 150 | gl.glGenBuffers(Buffer.MAX, bufferName); 151 | 152 | gl.glBindBuffer(GL_ARRAY_BUFFER, bufferName.get(Buffer.VERTEX)); 153 | gl.glBufferData(GL_ARRAY_BUFFER, vertexBuffer.capacity() * Float.BYTES, vertexBuffer, GL_STATIC_DRAW); 154 | gl.glBindBuffer(GL_ARRAY_BUFFER, 0); 155 | 156 | gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferName.get(Buffer.ELEMENT)); 157 | gl.glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementBuffer.capacity() * Short.BYTES, elementBuffer, GL_STATIC_DRAW); 158 | gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 159 | 160 | 161 | gl.glBindBuffer(GL_UNIFORM_BUFFER, bufferName.get(Buffer.GLOBAL_MATRICES)); 162 | gl.glBufferData(GL_UNIFORM_BUFFER, Mat4x4.SIZE * 2, null, GL_STREAM_DRAW); 163 | gl.glBindBuffer(GL_UNIFORM_BUFFER, 0); 164 | 165 | gl.glBindBufferBase(GL_UNIFORM_BUFFER, Semantic.Uniform.GLOBAL_MATRICES, bufferName.get(Buffer.GLOBAL_MATRICES)); 166 | 167 | 168 | destroyBuffers(vertexBuffer, elementBuffer); 169 | 170 | checkError(gl, "initBuffers"); 171 | } 172 | 173 | private void initVertexArray(GL3 gl) { 174 | 175 | gl.glGenVertexArrays(1, vertexArrayName); 176 | gl.glBindVertexArray(vertexArrayName.get(0)); 177 | { 178 | gl.glBindBuffer(GL_ARRAY_BUFFER, bufferName.get(Buffer.VERTEX)); 179 | { 180 | int stride = Vec2.SIZE * 2; 181 | int offset = 0; 182 | 183 | gl.glEnableVertexAttribArray(Semantic.Attr.POSITION); 184 | gl.glVertexAttribPointer(Semantic.Attr.POSITION, Vec2.length, GL_FLOAT, false, stride, offset); 185 | 186 | offset = Vec2.SIZE; 187 | gl.glEnableVertexAttribArray(Semantic.Attr.TEXCOORD); 188 | gl.glVertexAttribPointer(Semantic.Attr.TEXCOORD, Vec2.length, GL_FLOAT, false, stride, offset); 189 | } 190 | gl.glBindBuffer(GL_ARRAY_BUFFER, 0); 191 | 192 | gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferName.get(Buffer.ELEMENT)); 193 | } 194 | gl.glBindVertexArray(0); 195 | 196 | checkError(gl, "initVao"); 197 | } 198 | 199 | private void initTexture(GL3 gl) { 200 | 201 | try { 202 | URL texture = getClass().getClassLoader().getResource("images/door.png"); 203 | 204 | /* Texture data is an object containing all the relevant information about texture. */ 205 | TextureData data = TextureIO.newTextureData(gl.getGLProfile(), texture, false, TextureIO.PNG); 206 | 207 | int level = 0; 208 | 209 | gl.glGenTextures(1, textureName); 210 | 211 | gl.glBindTexture(GL_TEXTURE_2D, textureName.get(0)); 212 | { 213 | gl.glTexImage2D(GL_TEXTURE_2D, 214 | level, 215 | data.getInternalFormat(), 216 | data.getWidth(), data.getHeight(), 217 | data.getBorder(), 218 | data.getPixelFormat(), data.getPixelType(), 219 | data.getBuffer()); 220 | 221 | gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); 222 | gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level); 223 | 224 | IntBuffer swizzle = GLBuffers.newDirectIntBuffer(new int[]{GL_RED, GL_GREEN, GL_BLUE, GL_ONE}); 225 | gl.glTexParameterIiv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle); 226 | 227 | destroyBuffer(swizzle); 228 | } 229 | gl.glBindTexture(GL_TEXTURE_2D, 0); 230 | 231 | } catch (IOException ex) { 232 | Logger.getLogger(HelloTextureK.class.getName()).log(Level.SEVERE, null, ex); 233 | } 234 | } 235 | 236 | private void initSampler(GL3 gl) { 237 | 238 | gl.glGenSamplers(1, samplerName); 239 | 240 | gl.glSamplerParameteri(samplerName.get(0), GL_TEXTURE_MAG_FILTER, GL_NEAREST); 241 | gl.glSamplerParameteri(samplerName.get(0), GL_TEXTURE_MIN_FILTER, GL_NEAREST); 242 | 243 | gl.glSamplerParameteri(samplerName.get(0), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 244 | gl.glSamplerParameteri(samplerName.get(0), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 245 | } 246 | 247 | 248 | private void initProgram(GL3 gl) { 249 | 250 | program = new Program(gl, getClass(), "shaders/gl3", "hello-texture.vert", "hello-texture.frag", "modelToWorldMat", "diffuse"); 251 | 252 | gl.glUseProgram(program.name); 253 | 254 | gl.glUniform1i(program.get("diffuse"), Semantic.Sampler.DIFFUSE); 255 | gl.glUseProgram(0); 256 | 257 | int globalMatricesBI = gl.glGetUniformBlockIndex(program.name, "GlobalMatrices"); 258 | 259 | if (globalMatricesBI == -1) { 260 | System.err.println("block index 'GlobalMatrices' not found!"); 261 | } 262 | gl.glUniformBlockBinding(program.name, globalMatricesBI, Semantic.Uniform.GLOBAL_MATRICES); 263 | 264 | 265 | checkError(gl, "initProgram"); 266 | } 267 | 268 | @Override 269 | public void display(GLAutoDrawable drawable) { 270 | 271 | GL3 gl = drawable.getGL().getGL3(); 272 | 273 | // view matrix 274 | { 275 | Mat4x4 view = new Mat4x4(); 276 | view.to(matBuffer); 277 | 278 | gl.glBindBuffer(GL_UNIFORM_BUFFER, bufferName.get(Buffer.GLOBAL_MATRICES)); 279 | gl.glBufferSubData(GL_UNIFORM_BUFFER, Mat4x4.SIZE, Mat4x4.SIZE, matBuffer); 280 | gl.glBindBuffer(GL_UNIFORM_BUFFER, 0); 281 | } 282 | 283 | gl.glClearBufferfv(GL_COLOR, 0, clearColor.put(0, 0f).put(1, .33f).put(2, 0.66f).put(3, 1f)); 284 | gl.glClearBufferfv(GL_DEPTH, 0, clearDepth.put(0, 1f)); 285 | 286 | gl.glUseProgram(program.name); 287 | gl.glBindVertexArray(vertexArrayName.get(0)); 288 | 289 | // model matrix 290 | { 291 | long now = System.currentTimeMillis(); 292 | float diff = (float) (now - start) / 1_000f; 293 | 294 | Mat4x4 model = new Mat4x4(); 295 | model 296 | .scale(0.5f) 297 | .rotate(diff, 0f, 0f, 1f) 298 | .to(matBuffer); 299 | 300 | gl.glUniformMatrix4fv(program.get("modelToWorldMat"), 1, false, matBuffer); 301 | } 302 | 303 | gl.glActiveTexture(GL_TEXTURE0 + Semantic.Sampler.DIFFUSE); 304 | gl.glBindTexture(GL_TEXTURE_2D, textureName.get(0)); 305 | gl.glBindSampler(Semantic.Sampler.DIFFUSE, samplerName.get(0)); 306 | { 307 | gl.glDrawElements(GL_TRIANGLES, elementData.length, GL_UNSIGNED_SHORT, 0); 308 | } 309 | gl.glBindSampler(Semantic.Sampler.DIFFUSE, 0); 310 | gl.glBindTexture(GL_TEXTURE_2D, 0); 311 | 312 | gl.glUseProgram(0); 313 | gl.glBindVertexArray(0); 314 | 315 | checkError(gl, "display"); 316 | } 317 | 318 | @Override 319 | public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { 320 | 321 | GL3 gl = drawable.getGL().getGL3(); 322 | 323 | // ortho matrix 324 | glm.ortho(-1f, 1f, -1f, 1f, 1f, -1f).to(matBuffer); 325 | 326 | gl.glBindBuffer(GL_UNIFORM_BUFFER, bufferName.get(Buffer.GLOBAL_MATRICES)); 327 | gl.glBufferSubData(GL_UNIFORM_BUFFER, 0, Mat4x4.SIZE, matBuffer); 328 | gl.glBindBuffer(GL_UNIFORM_BUFFER, 0); 329 | 330 | gl.glViewport(x, y, width, height); 331 | 332 | checkError(gl, "reshape"); 333 | } 334 | 335 | @Override 336 | public void dispose(GLAutoDrawable drawable) { 337 | 338 | GL3 gl = drawable.getGL().getGL3(); 339 | 340 | gl.glDeleteProgram(program.name); 341 | gl.glDeleteVertexArrays(1, vertexArrayName); 342 | gl.glDeleteBuffers(Buffer.MAX, bufferName); 343 | gl.glDeleteTextures(1, textureName); 344 | gl.glDeleteSamplers(1, samplerName); 345 | 346 | destroyBuffers(vertexArrayName, bufferName, textureName, samplerName, matBuffer, clearColor, clearDepth); 347 | } 348 | 349 | 350 | @Override 351 | public void keyPressed(KeyEvent e) { 352 | if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { 353 | new Thread(() -> { 354 | window.destroy(); 355 | }).start(); 356 | } 357 | } 358 | 359 | @Override 360 | public void keyReleased(KeyEvent e) { 361 | } 362 | } -------------------------------------------------------------------------------- /src/main/kotlin/gl3/helloTexture.kt: -------------------------------------------------------------------------------- 1 | package gl3 2 | 3 | import com.jogamp.newt.event.KeyEvent 4 | import com.jogamp.newt.event.KeyListener 5 | import com.jogamp.newt.event.WindowAdapter 6 | import com.jogamp.newt.event.WindowEvent 7 | import com.jogamp.newt.opengl.GLWindow 8 | import com.jogamp.opengl.* 9 | import com.jogamp.opengl.GL2ES2.GL_RED 10 | import com.jogamp.opengl.GL2ES2.GL_STREAM_DRAW 11 | import com.jogamp.opengl.GL2ES3.* 12 | import com.jogamp.opengl.GL2GL3.GL_TEXTURE_SWIZZLE_RGBA 13 | import com.jogamp.opengl.util.Animator 14 | import com.jogamp.opengl.util.texture.TextureIO 15 | import framework.Semantic 16 | import glm.L 17 | import glm.SIZE 18 | import glm.f 19 | import glm.glm 20 | import glm.mat.Mat4 21 | import glm.vec._2.Vec2 22 | import glm.vec._4.Vec4 23 | import uno.buffer.* 24 | import uno.gl.checkError 25 | import uno.glsl.Program 26 | import kotlin.properties.Delegates 27 | 28 | /** 29 | * Created by elect on 06/03/17. 30 | */ 31 | 32 | fun main(args: Array) { 33 | HelloTextureK().setup() 34 | } 35 | 36 | class HelloTextureK : GLEventListener, KeyListener { 37 | 38 | var window by Delegates.notNull() 39 | val animator = Animator() 40 | 41 | val vertexData = floatArrayOf( 42 | -1f, -1f, 0f, 0f, 43 | -1f, +1f, 0f, 1f, 44 | +1f, +1f, 1f, 1f, 45 | +1f, -1f, 1f, 0f) 46 | 47 | val elementData = shortArrayOf(0, 1, 3, 1, 2, 3) 48 | 49 | object Buffer { 50 | val VERTEX = 0 51 | val ELEMENT = 1 52 | val GLOBAL_MATRICES = 2 53 | val MAX = 3 54 | } 55 | 56 | val bufferName = intBufferBig(Buffer.MAX) 57 | val vertexArrayName = intBufferBig(1) 58 | 59 | val textureName = intBufferBig(1) 60 | val samplerName = intBufferBig(1) 61 | 62 | val clearColor = floatBufferBig(Vec4.length) 63 | val clearDepth = floatBufferBig(1) 64 | 65 | val matBuffer = floatBufferBig(16) 66 | 67 | var program by Delegates.notNull() 68 | 69 | var start = 0L 70 | 71 | fun setup() { 72 | 73 | val glProfile = GLProfile.get(GLProfile.GL3) 74 | val glCapabilities = GLCapabilities(glProfile) 75 | 76 | window = GLWindow.create(glCapabilities) 77 | 78 | window.title = "Hello Texture" 79 | window.setSize(1024, 768) 80 | 81 | window.isVisible = true 82 | 83 | window.addGLEventListener(this) 84 | window.addKeyListener(this) 85 | 86 | animator.add(window) 87 | animator.start() 88 | 89 | window.addWindowListener(object : WindowAdapter() { 90 | override fun windowDestroyed(e: WindowEvent?) { 91 | animator.stop(); System.exit(1); } 92 | }) 93 | 94 | } 95 | 96 | override fun init(drawable: GLAutoDrawable) { 97 | 98 | val gl = drawable.gl.gL3 99 | 100 | initBuffers(gl) 101 | 102 | initVertexArray(gl) 103 | 104 | initTexture(gl) 105 | 106 | initSampler(gl) 107 | 108 | initProgram(gl) 109 | 110 | gl.glEnable(GL_DEPTH_TEST) 111 | 112 | start = System.currentTimeMillis() 113 | } 114 | 115 | fun initBuffers(gl: GL3) = with(gl) { 116 | 117 | val vertexBuffer = vertexData.toFloatBuffer() 118 | val elementBuffer = elementData.toShortBuffer() 119 | val globalMatricesBuffer = floatBufferBig(16 * 2) 120 | 121 | glGenBuffers(Buffer.MAX, bufferName) 122 | 123 | glBindBuffer(GL_ARRAY_BUFFER, bufferName[Buffer.VERTEX]) 124 | glBufferData(GL_ARRAY_BUFFER, vertexBuffer.SIZE.L, vertexBuffer, GL_STATIC_DRAW) 125 | glBindBuffer(GL_ARRAY_BUFFER, 0) 126 | 127 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferName[Buffer.ELEMENT]) 128 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementBuffer.SIZE.L, elementBuffer, GL_STATIC_DRAW) 129 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) 130 | 131 | 132 | glBindBuffer(GL_UNIFORM_BUFFER, bufferName[Buffer.GLOBAL_MATRICES]) 133 | glBufferData(GL_UNIFORM_BUFFER, globalMatricesBuffer.SIZE.L, null, GL_STREAM_DRAW) 134 | glBindBuffer(GL_UNIFORM_BUFFER, 0) 135 | 136 | glBindBufferBase(GL_UNIFORM_BUFFER, Semantic.Uniform.GLOBAL_MATRICES, bufferName[Buffer.GLOBAL_MATRICES]) 137 | 138 | 139 | vertexBuffer.destroy() 140 | elementBuffer.destroy() 141 | globalMatricesBuffer.destroy() 142 | 143 | checkError(gl, "initBuffers") 144 | } 145 | 146 | fun initVertexArray(gl: GL3) = with(gl) { 147 | 148 | glGenVertexArrays(1, vertexArrayName) 149 | glBindVertexArray(vertexArrayName[0]) 150 | 151 | run { 152 | 153 | glBindBuffer(GL_ARRAY_BUFFER, bufferName[Buffer.VERTEX]) 154 | 155 | run { 156 | val stride = Vec2.SIZE * 2 157 | var offset = 0 158 | 159 | glEnableVertexAttribArray(Semantic.Attr.POSITION) 160 | glVertexAttribPointer(Semantic.Attr.POSITION, Vec2.length, GL_FLOAT, false, stride, offset.L) 161 | 162 | offset = Vec2.SIZE 163 | glEnableVertexAttribArray(Semantic.Attr.TEXCOORD) 164 | glVertexAttribPointer(Semantic.Attr.TEXCOORD, Vec2.length, GL_FLOAT, false, stride, offset.L) 165 | } 166 | glBindBuffer(GL_ARRAY_BUFFER, 0) 167 | 168 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferName[Buffer.ELEMENT]) 169 | } 170 | glBindVertexArray(0) 171 | 172 | checkError(gl, "initVao") 173 | } 174 | 175 | fun initTexture(gl: GL3) = with(gl) { 176 | 177 | val texture = this::class.java.classLoader.getResource("images/door.png") 178 | 179 | /* Texture data is an object containing all the relevant information about texture. */ 180 | val data = TextureIO.newTextureData(gl.glProfile, texture!!, false, TextureIO.PNG) 181 | 182 | // We don't use multiple levels (mipmaps) here, then our maximum level is zero. 183 | val level = 0 184 | 185 | glGenTextures(1, textureName) 186 | 187 | glBindTexture(GL_TEXTURE_2D, textureName[0]) 188 | 189 | run { 190 | /* In this example internal format is GL_RGB8, dimensions are 512 x 512, border should always be zero, 191 | pixelFormat GL_RGB, pixelType GL_UNSIGNED_BYTE. */ 192 | glTexImage2D(GL_TEXTURE_2D, 193 | level, 194 | data.internalFormat, 195 | data.width, data.height, 196 | data.border, 197 | data.pixelFormat, data.pixelType, 198 | data.buffer) 199 | 200 | // We set the base and max level. 201 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0) 202 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level) 203 | 204 | /* We set the swizzling. Since it is an RGB texture, we can choose to make the missing component alpha 205 | equal to one. */ 206 | val swizzle = intBufferOf(GL_RED, GL_GREEN, GL_BLUE, GL_ONE) 207 | glTexParameterIiv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle) 208 | 209 | swizzle.destroy() 210 | } 211 | glBindTexture(GL_TEXTURE_2D, 0) 212 | } 213 | 214 | fun initSampler(gl: GL3) = with(gl) { 215 | 216 | /* As with most OpenGL objects, we create a sampler object with glGenSamplers. However, notice something unusual 217 | with the next series of functions. We do not bind a sampler to the context to set parameters in it, nor does 218 | glSamplerParameter take a context target. We simply pass an object directly to the function. */ 219 | glGenSamplers(1, samplerName) 220 | 221 | glSamplerParameteri(samplerName[0], GL_TEXTURE_MAG_FILTER, GL_NEAREST) 222 | glSamplerParameteri(samplerName[0], GL_TEXTURE_MIN_FILTER, GL_NEAREST) 223 | 224 | /* OpenGL names the components of the texture coordinate “strq” rather than “xyzw” or “uvw” as is common. 225 | Indeed, OpenGL has two different names for the components: “strq” is used in the main API, but “stpq” is used in 226 | GLSL shaders. Much like “rgba”, you can use “stpq” as swizzle selectors for any vector instead of the 227 | traditional “xyzw”. 228 | The reason for the odd naming is that OpenGL tries to keep vector suffixes from conflicting. “uvw” does not work 229 | because “w” is already part of the “xyzw” suffix. In GLSL, the “r” in “strq” conflicts with “rgba”, so they had 230 | to go with “stpq” instead. */ 231 | glSamplerParameteri(samplerName[0], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) 232 | glSamplerParameteri(samplerName[0], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) 233 | } 234 | 235 | 236 | fun initProgram(gl: GL3) = with(gl) { 237 | 238 | program = Program(gl, this::class.java, "shaders/gl3", "hello-texture.vert", "hello-texture.frag", "model", "diffuse") 239 | 240 | glUseProgram(program.name) 241 | /* We bind the uniform texture0UL to the Texture Image Units zero or, in other words, Semantic.Uniform.TEXTURE0. */ 242 | glUniform1i(program["diffuse"], Semantic.Sampler.DIFFUSE) 243 | glUseProgram(0) 244 | 245 | val globalMatricesBI = glGetUniformBlockIndex(program.name, "GlobalMatrices") 246 | 247 | if (globalMatricesBI == -1) { 248 | System.err.println("block index 'GlobalMatrices' not found!") 249 | } 250 | glUniformBlockBinding(program.name, globalMatricesBI, Semantic.Uniform.GLOBAL_MATRICES) 251 | 252 | checkError(gl, "initProgram") 253 | } 254 | 255 | override fun display(drawable: GLAutoDrawable) = with(drawable.gl.gL3) { 256 | 257 | // update view matrix 258 | run { 259 | val view = Mat4() 260 | view to matBuffer 261 | 262 | glBindBuffer(GL_UNIFORM_BUFFER, bufferName[Buffer.GLOBAL_MATRICES]) 263 | glBufferSubData(GL_UNIFORM_BUFFER, Mat4.SIZE.L, Mat4.SIZE.L, matBuffer) 264 | glBindBuffer(GL_UNIFORM_BUFFER, 0) 265 | } 266 | 267 | // We clear color and depth (although depth is not necessary since it is 1 by default). 268 | glClearBufferfv(GL_COLOR, 0, clearColor.put(0f, .33f, 0.66f, 1f)) 269 | glClearBufferfv(GL_DEPTH, 0, clearDepth.put(0, 1f)) 270 | 271 | glUseProgram(program.name) 272 | glBindVertexArray(vertexArrayName[0]) 273 | 274 | // update model matrix based on time 275 | run { 276 | val now = System.currentTimeMillis() 277 | val diff = (now - start).f / 1_000f 278 | 279 | // Here we build the matrix that will multiply our original vertex positions. We scale, half and rotate it. 280 | val model = Mat4() 281 | .scale_(0.5f) 282 | .rotate_(diff, 0f, 0f, 1f) 283 | 284 | glUniformMatrix4fv(program["model"], 1, false, model to matBuffer) 285 | } 286 | 287 | /* The glActiveTexture function changes the current texture unit. All subsequent texture operations, whether 288 | glBindTexture, glTexImage, glTexParameter, etc, affect the texture bound to the current texture unit. 289 | 290 | What this means is that if you want to modify a texture, you must overwrite a texture unit that may already 291 | be bound. This is usually not a huge problem, because you rarely modify textures in the same area of code 292 | used to render. But you should be aware of this. 293 | 294 | Also note the peculiar glActiveTexture syntax for specifying the image unit: GL_TEXTURE0 + 295 | Semantic.Uniform.TEXTURE0. This is the correct way to specify which texture unit, because glActiveTexture is 296 | defined in terms of an enumerator rather than integer texture image units. */ 297 | glActiveTexture(GL_TEXTURE0 + Semantic.Sampler.DIFFUSE) 298 | glBindTexture(GL_TEXTURE_2D, textureName[0]) 299 | glBindSampler(Semantic.Sampler.DIFFUSE, samplerName[0]) 300 | 301 | glDrawElements(GL_TRIANGLES, elementData.size, GL_UNSIGNED_SHORT, 0) 302 | 303 | glBindSampler(Semantic.Sampler.DIFFUSE, 0) 304 | glBindTexture(GL_TEXTURE_2D, 0) 305 | 306 | /* The following line binds VAO and program to the default values, this is not a free operation, it costs always 307 | (although very small). Every binding means additional validation and overhead, this may affect your 308 | performances in very specific scenario. So you should reduce these calls, but remember that OpenGL is a state 309 | machine, so what you left bound remains bound! */ 310 | glUseProgram(0) 311 | glBindVertexArray(0) 312 | 313 | /* Check always any GL error, but keep in mind this is an implicit synchronization between CPU and GPU, so you 314 | should use it only for debug purposes. */ 315 | checkError(gl, "display") 316 | } 317 | 318 | override fun reshape(drawable: GLAutoDrawable, x: Int, y: Int, width: Int, height: Int) = with(drawable.gl.gL3) { 319 | 320 | glm.ortho(-1f, 1f, -1f, 1f, 1f, -1f) to matBuffer 321 | 322 | glBindBuffer(GL_UNIFORM_BUFFER, bufferName[Buffer.GLOBAL_MATRICES]) 323 | glBufferSubData(GL_UNIFORM_BUFFER, 0, Mat4.SIZE.L, matBuffer) 324 | glBindBuffer(GL_UNIFORM_BUFFER, 0) 325 | 326 | glViewport(x, y, width, height) 327 | 328 | checkError(gl, "reshape") 329 | } 330 | 331 | override fun dispose(drawable: GLAutoDrawable) = with(drawable.gl.gL3) { 332 | 333 | glDeleteProgram(program.name) 334 | glDeleteVertexArrays(1, vertexArrayName) 335 | glDeleteBuffers(Buffer.MAX, bufferName) 336 | glDeleteTextures(1, textureName) 337 | glDeleteSamplers(1, samplerName) 338 | 339 | destroyBuffers(vertexArrayName, bufferName, textureName, samplerName, matBuffer, clearColor, clearDepth) 340 | } 341 | 342 | 343 | override fun keyPressed(e: KeyEvent) { 344 | if (e.keyCode == KeyEvent.VK_ESCAPE) { 345 | /* Note: calling System.exit() synchronously inside the draw, reshape or init callbacks can lead to 346 | deadlocks on certain platforms (in particular, X11) because the JAWT's locking routines cause a global 347 | AWT lock to be grabbed. Run the exit routine in another thread. */ 348 | Thread { window.destroy() }.start() 349 | } 350 | } 351 | 352 | override fun keyReleased(e: KeyEvent) {} 353 | } -------------------------------------------------------------------------------- /src/main/java/gl4/HelloTriangleSimple.java: -------------------------------------------------------------------------------- 1 | package gl4; 2 | 3 | import com.jogamp.newt.event.*; 4 | import com.jogamp.newt.opengl.GLWindow; 5 | import com.jogamp.opengl.*; 6 | import com.jogamp.opengl.math.FloatUtil; 7 | import com.jogamp.opengl.util.Animator; 8 | import com.jogamp.opengl.util.GLBuffers; 9 | import com.jogamp.opengl.util.glsl.ShaderCode; 10 | import com.jogamp.opengl.util.glsl.ShaderProgram; 11 | import framework.Semantic; 12 | 13 | import java.nio.ByteBuffer; 14 | import java.nio.FloatBuffer; 15 | import java.nio.IntBuffer; 16 | import java.nio.ShortBuffer; 17 | 18 | import static com.jogamp.opengl.GL.*; 19 | import static com.jogamp.opengl.GL.GL_FLOAT; 20 | import static com.jogamp.opengl.GL.GL_TRIANGLES; 21 | import static com.jogamp.opengl.GL.GL_UNSIGNED_SHORT; 22 | import static com.jogamp.opengl.GL2ES2.GL_DEBUG_SEVERITY_HIGH; 23 | import static com.jogamp.opengl.GL2ES2.GL_DEBUG_SEVERITY_MEDIUM; 24 | import static com.jogamp.opengl.GL2ES3.*; 25 | import static com.jogamp.opengl.GL2ES3.GL_UNIFORM_BUFFER; 26 | import static com.jogamp.opengl.GL4.GL_MAP_COHERENT_BIT; 27 | import static com.jogamp.opengl.GL4.GL_MAP_PERSISTENT_BIT; 28 | 29 | /** 30 | * Created by GBarbieri on 16.03.2017. 31 | */ 32 | public class HelloTriangleSimple implements GLEventListener, KeyListener { 33 | 34 | private static GLWindow window; 35 | private static Animator animator; 36 | 37 | public static void main(String[] args) { 38 | new HelloTriangleSimple().setup(); 39 | } 40 | 41 | private float[] vertexData = { 42 | -1, -1, 1, 0, 0, 43 | +0, +2, 0, 0, 1, 44 | +1, -1, 0, 1, 0}; 45 | 46 | private short[] elementData = {0, 2, 1}; 47 | 48 | private interface Buffer { 49 | 50 | int VERTEX = 0; 51 | int ELEMENT = 1; 52 | int GLOBAL_MATRICES = 2; 53 | int MODEL_MATRIX = 3; 54 | int MAX = 4; 55 | } 56 | 57 | private IntBuffer bufferName = GLBuffers.newDirectIntBuffer(Buffer.MAX); 58 | private IntBuffer vertexArrayName = GLBuffers.newDirectIntBuffer(1); 59 | 60 | private FloatBuffer clearColor = GLBuffers.newDirectFloatBuffer(4); 61 | private FloatBuffer clearDepth = GLBuffers.newDirectFloatBuffer(1); 62 | 63 | private FloatBuffer matBuffer = GLBuffers.newDirectFloatBuffer(16); 64 | 65 | private ByteBuffer globalMatricesPointer, modelMatrixPointer; 66 | // https://jogamp.org/bugzilla/show_bug.cgi?id=1287 67 | private boolean bug1287 = true; 68 | 69 | private Program program; 70 | 71 | private long start; 72 | 73 | 74 | private void setup() { 75 | 76 | GLProfile glProfile = GLProfile.get(GLProfile.GL3); 77 | GLCapabilities glCapabilities = new GLCapabilities(glProfile); 78 | 79 | window = GLWindow.create(glCapabilities); 80 | 81 | window.setTitle("Hello Triangle (enhanced)"); 82 | window.setSize(1024, 768); 83 | 84 | window.setContextCreationFlags(GLContext.CTX_OPTION_DEBUG); 85 | window.setVisible(true); 86 | 87 | window.addGLEventListener(this); 88 | window.addKeyListener(this); 89 | 90 | animator = new Animator(window); 91 | animator.start(); 92 | 93 | window.addWindowListener(new WindowAdapter() { 94 | @Override 95 | public void windowDestroyed(WindowEvent e) { 96 | animator.stop(); 97 | System.exit(1); 98 | } 99 | }); 100 | } 101 | 102 | 103 | @Override 104 | public void init(GLAutoDrawable drawable) { 105 | 106 | GL4 gl = drawable.getGL().getGL4(); 107 | 108 | initDebug(gl); 109 | 110 | initBuffers(gl); 111 | 112 | initVertexArray(gl); 113 | 114 | program = new Program(gl, "shaders/gl4", "hello-triangle", "hello-triangle"); 115 | 116 | gl.glEnable(GL_DEPTH_TEST); 117 | 118 | start = System.currentTimeMillis(); 119 | } 120 | 121 | private void initDebug(GL4 gl) { 122 | 123 | window.getContext().addGLDebugListener(new GLDebugListener() { 124 | @Override 125 | public void messageSent(GLDebugMessage event) { 126 | System.out.println(event); 127 | } 128 | }); 129 | 130 | gl.glDebugMessageControl( 131 | GL_DONT_CARE, 132 | GL_DONT_CARE, 133 | GL_DONT_CARE, 134 | 0, 135 | null, 136 | false); 137 | 138 | gl.glDebugMessageControl( 139 | GL_DONT_CARE, 140 | GL_DONT_CARE, 141 | GL_DEBUG_SEVERITY_HIGH, 142 | 0, 143 | null, 144 | true); 145 | 146 | gl.glDebugMessageControl( 147 | GL_DONT_CARE, 148 | GL_DONT_CARE, 149 | GL_DEBUG_SEVERITY_MEDIUM, 150 | 0, 151 | null, 152 | true); 153 | } 154 | 155 | private void initBuffers(GL4 gl) { 156 | 157 | FloatBuffer vertexBuffer = GLBuffers.newDirectFloatBuffer(vertexData); 158 | ShortBuffer elementBuffer = GLBuffers.newDirectShortBuffer(elementData); 159 | 160 | gl.glCreateBuffers(Buffer.MAX, bufferName); 161 | 162 | if (!bug1287) { 163 | 164 | gl.glNamedBufferStorage(bufferName.get(Buffer.VERTEX), vertexBuffer.capacity() * Float.BYTES, vertexBuffer, 165 | GL_STATIC_DRAW); 166 | gl.glNamedBufferStorage(bufferName.get(Buffer.ELEMENT), elementBuffer.capacity() * Short.BYTES, 167 | elementBuffer, GL_STATIC_DRAW); 168 | 169 | gl.glNamedBufferStorage(bufferName.get(Buffer.GLOBAL_MATRICES), 16 * 4 * 2, null, GL_MAP_WRITE_BIT); 170 | gl.glNamedBufferStorage(bufferName.get(Buffer.MODEL_MATRIX), 16 * 4, null, GL_MAP_WRITE_BIT); 171 | 172 | } else { 173 | 174 | gl.glBindBuffer(GL_ARRAY_BUFFER, bufferName.get(Buffer.VERTEX)); 175 | gl.glBufferStorage(GL_ARRAY_BUFFER, vertexBuffer.capacity() * Float.BYTES, vertexBuffer, 0); 176 | gl.glBindBuffer(GL_ARRAY_BUFFER, 0); 177 | 178 | gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferName.get(Buffer.ELEMENT)); 179 | gl.glBufferStorage(GL_ELEMENT_ARRAY_BUFFER, elementBuffer.capacity() * Short.BYTES, elementBuffer, 0); 180 | gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 181 | 182 | 183 | IntBuffer uniformBufferOffset = GLBuffers.newDirectIntBuffer(1); 184 | gl.glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, uniformBufferOffset); 185 | int globalBlockSize = Math.max(16 * 4 * 2, uniformBufferOffset.get(0)); 186 | int modelBlockSize = Math.max(16 * 4, uniformBufferOffset.get(0)); 187 | 188 | gl.glBindBuffer(GL_UNIFORM_BUFFER, bufferName.get(Buffer.GLOBAL_MATRICES)); 189 | gl.glBufferStorage(GL_UNIFORM_BUFFER, globalBlockSize, null, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); 190 | gl.glBindBuffer(GL_UNIFORM_BUFFER, 0); 191 | 192 | gl.glBindBuffer(GL_UNIFORM_BUFFER, bufferName.get(Buffer.MODEL_MATRIX)); 193 | gl.glBufferStorage(GL_UNIFORM_BUFFER, modelBlockSize, null, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); 194 | gl.glBindBuffer(GL_UNIFORM_BUFFER, 0); 195 | } 196 | 197 | // map the transform buffers and keep them mapped 198 | globalMatricesPointer = gl.glMapNamedBufferRange( 199 | bufferName.get(Buffer.GLOBAL_MATRICES), 200 | 0, 201 | 16 * 4 * 2, 202 | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); // flags 203 | 204 | modelMatrixPointer = gl.glMapNamedBufferRange( 205 | bufferName.get(Buffer.MODEL_MATRIX), 206 | 0, 207 | 16 * 4, 208 | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); 209 | } 210 | 211 | private void initVertexArray(GL4 gl) { 212 | 213 | gl.glCreateVertexArrays(1, vertexArrayName); 214 | 215 | gl.glVertexArrayAttribBinding(vertexArrayName.get(0), Semantic.Attr.POSITION, Semantic.Stream.A); 216 | gl.glVertexArrayAttribBinding(vertexArrayName.get(0), Semantic.Attr.COLOR, Semantic.Stream.A); 217 | 218 | gl.glVertexArrayAttribFormat(vertexArrayName.get(0), Semantic.Attr.POSITION, 2, GL_FLOAT, false, 0); 219 | gl.glVertexArrayAttribFormat(vertexArrayName.get(0), Semantic.Attr.COLOR, 3, GL_FLOAT, false, 2 * 4); 220 | 221 | gl.glEnableVertexArrayAttrib(vertexArrayName.get(0), Semantic.Attr.POSITION); 222 | gl.glEnableVertexArrayAttrib(vertexArrayName.get(0), Semantic.Attr.COLOR); 223 | 224 | gl.glVertexArrayElementBuffer(vertexArrayName.get(0), bufferName.get(Buffer.ELEMENT)); 225 | gl.glVertexArrayVertexBuffer(vertexArrayName.get(0), Semantic.Stream.A, bufferName.get(Buffer.VERTEX), 0, (2 + 3) * 4); 226 | } 227 | 228 | @Override 229 | public void display(GLAutoDrawable drawable) { 230 | 231 | GL4 gl = drawable.getGL().getGL4(); 232 | 233 | 234 | // view matrix 235 | { 236 | float[] view = FloatUtil.makeIdentity(new float[16]); 237 | for (int i = 0; i < 16; i++) 238 | globalMatricesPointer.putFloat(16 * 4 + i * 4, view[i]); 239 | } 240 | 241 | 242 | gl.glClearBufferfv(GL_COLOR, 0, clearColor.put(0, 1f).put(1, .5f).put(2, 0f).put(3, 1f)); 243 | gl.glClearBufferfv(GL_DEPTH, 0, clearDepth.put(0, 1f)); 244 | 245 | // model matrix 246 | { 247 | long now = System.currentTimeMillis(); 248 | float diff = (float) (now - start) / 1_000; 249 | 250 | float[] scale = FloatUtil.makeScale(new float[16], true, 0.5f, 0.5f, 0.5f); 251 | float[] rotateZ = FloatUtil.makeRotationAxis(new float[16], 0, diff, 0f, 0f, 1f, new float[3]); 252 | float[] model = FloatUtil.multMatrix(scale, rotateZ); 253 | modelMatrixPointer.asFloatBuffer().put(model); 254 | } 255 | 256 | gl.glUseProgram(program.name); 257 | gl.glBindVertexArray(vertexArrayName.get(0)); 258 | 259 | gl.glBindBufferBase( 260 | GL_UNIFORM_BUFFER, 261 | Semantic.Uniform.TRANSFORM0, 262 | bufferName.get(Buffer.GLOBAL_MATRICES)); 263 | 264 | gl.glBindBufferBase( 265 | GL_UNIFORM_BUFFER, 266 | Semantic.Uniform.TRANSFORM1, 267 | bufferName.get(Buffer.MODEL_MATRIX)); 268 | 269 | gl.glDrawElements( 270 | GL_TRIANGLES, 271 | elementData.length, 272 | GL_UNSIGNED_SHORT, 273 | 0); 274 | 275 | gl.glUseProgram(0); 276 | gl.glBindVertexArray(0); 277 | } 278 | 279 | @Override 280 | public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { 281 | 282 | GL4 gl = drawable.getGL().getGL4(); 283 | 284 | // ortho matrix 285 | float[] ortho = FloatUtil.makeOrtho(new float[16], 0, false, -1f, 1f, -1f, 1f, 1f, -1f); 286 | globalMatricesPointer.asFloatBuffer().put(ortho); 287 | 288 | gl.glViewport(x, y, width, height); 289 | } 290 | 291 | @Override 292 | public void dispose(GLAutoDrawable drawable) { 293 | 294 | GL4 gl = drawable.getGL().getGL4(); 295 | 296 | gl.glUnmapNamedBuffer(bufferName.get(Buffer.GLOBAL_MATRICES)); 297 | gl.glUnmapNamedBuffer(bufferName.get(Buffer.MODEL_MATRIX)); 298 | 299 | gl.glDeleteProgram(program.name); 300 | gl.glDeleteVertexArrays(1, vertexArrayName); 301 | gl.glDeleteBuffers(Buffer.MAX, bufferName); 302 | } 303 | 304 | @Override 305 | public void keyPressed(KeyEvent e) { 306 | if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { 307 | new Thread(() -> { 308 | window.destroy(); 309 | }).start(); 310 | } 311 | } 312 | 313 | @Override 314 | public void keyReleased(KeyEvent e) { 315 | } 316 | 317 | private class Program { 318 | 319 | public int name = 0; 320 | 321 | public Program(GL4 gl, String root, String vertex, String fragment) { 322 | 323 | ShaderCode vertShader = ShaderCode.create(gl, GL_VERTEX_SHADER, this.getClass(), root, null, vertex, 324 | "vert", null, true); 325 | ShaderCode fragShader = ShaderCode.create(gl, GL_FRAGMENT_SHADER, this.getClass(), root, null, fragment, 326 | "frag", null, true); 327 | 328 | ShaderProgram shaderProgram = new ShaderProgram(); 329 | 330 | shaderProgram.add(vertShader); 331 | shaderProgram.add(fragShader); 332 | 333 | shaderProgram.init(gl); 334 | 335 | name = shaderProgram.program(); 336 | 337 | shaderProgram.link(gl, System.err); 338 | } 339 | } 340 | 341 | private class GlDebugOutput implements GLDebugListener { 342 | 343 | private int source = 0; 344 | private int type = 0; 345 | private int id = 0; 346 | private int severity = 0; 347 | private int length = 0; 348 | private String message = null; 349 | private boolean received = false; 350 | 351 | public GlDebugOutput() { 352 | } 353 | 354 | public GlDebugOutput(int source, int type, int severity) { 355 | this.source = source; 356 | this.type = type; 357 | this.severity = severity; 358 | this.message = null; 359 | this.id = -1; 360 | } 361 | 362 | public GlDebugOutput(String message, int id) { 363 | this.source = -1; 364 | this.type = -1; 365 | this.severity = -1; 366 | this.message = message; 367 | this.id = id; 368 | } 369 | 370 | @Override 371 | public void messageSent(GLDebugMessage event) { 372 | 373 | if (event.getDbgSeverity() == GL_DEBUG_SEVERITY_LOW || event.getDbgSeverity() == GL_DEBUG_SEVERITY_NOTIFICATION) 374 | System.out.println("GlDebugOutput.messageSent(): " + event); 375 | else 376 | System.err.println("GlDebugOutput.messageSent(): " + event); 377 | 378 | if (null != message && message == event.getDbgMsg() && id == event.getDbgId()) 379 | received = true; 380 | else if (0 <= source && source == event.getDbgSource() && type == event.getDbgType() && severity == event.getDbgSeverity()) 381 | received = true; 382 | } 383 | } 384 | } -------------------------------------------------------------------------------- /src/main/kotlin/gl4/helloGlobe.kt: -------------------------------------------------------------------------------- 1 | package gl4 2 | 3 | import com.jogamp.newt.event.KeyEvent 4 | import com.jogamp.newt.event.KeyListener 5 | import com.jogamp.newt.event.WindowAdapter 6 | import com.jogamp.newt.event.WindowEvent 7 | import com.jogamp.newt.opengl.GLWindow 8 | import com.jogamp.opengl.* 9 | import com.jogamp.opengl.GL2ES2.GL_DEBUG_SEVERITY_HIGH 10 | import com.jogamp.opengl.GL2ES2.GL_DEBUG_SEVERITY_MEDIUM 11 | import com.jogamp.opengl.GL2ES3.* 12 | import com.jogamp.opengl.GL4.GL_MAP_COHERENT_BIT 13 | import com.jogamp.opengl.GL4.GL_MAP_PERSISTENT_BIT 14 | import com.jogamp.opengl.util.Animator 15 | import com.jogamp.opengl.util.texture.TextureIO 16 | import framework.Semantic 17 | import glm.* 18 | import glm.mat.Mat4 19 | import glm.vec._2.Vec2 20 | import glm.vec._3.Vec3 21 | import glm.vec._4.Vec4 22 | import uno.buffer.* 23 | import uno.debug.GlDebugOutput 24 | import uno.glsl.Program 25 | import java.nio.ByteBuffer 26 | import java.nio.FloatBuffer 27 | import java.nio.ShortBuffer 28 | import kotlin.properties.Delegates 29 | 30 | fun main(args: Array) { 31 | HelloGlobe_().setup() 32 | } 33 | 34 | class HelloGlobe_ : GLEventListener, KeyListener { 35 | 36 | var window by Delegates.notNull() 37 | val animator = Animator() 38 | 39 | object Buffer { 40 | val VERTEX = 0 41 | val ELEMENT = 1 42 | val GLOBAL_MATRICES = 2 43 | val MODEL_MATRIX = 3 44 | val MAX = 4 45 | } 46 | 47 | val bufferName = intBufferBig(Buffer.MAX) 48 | val vertexArrayName = intBufferBig(1) 49 | 50 | val textureName = intBufferBig(1) 51 | val samplerName = intBufferBig(1) 52 | 53 | val clearColor = floatBufferBig(Vec4.length) 54 | val clearDepth = floatBufferBig(1) 55 | 56 | var globalMatricesPointer by Delegates.notNull() 57 | var modelMatrixPointer by Delegates.notNull() 58 | 59 | // https://jogamp.org/bugzilla/show_bug.cgi?id=1287 60 | val bug1287 = true 61 | 62 | var program by Delegates.notNull() 63 | 64 | var start = 0L 65 | 66 | var elementCount = 0 67 | 68 | fun setup() { 69 | 70 | val glProfile = GLProfile.get(GLProfile.GL3) 71 | val glCapabilities = GLCapabilities(glProfile) 72 | 73 | window = GLWindow.create(glCapabilities) 74 | 75 | window.title = "Hello Globe" 76 | window.setSize(1024, 768) 77 | 78 | window.contextCreationFlags = GLContext.CTX_OPTION_DEBUG 79 | window.isVisible = true 80 | 81 | window.addGLEventListener(this) 82 | window.addKeyListener(this) 83 | 84 | animator.add(window) 85 | animator.start() 86 | 87 | window.addWindowListener(object : WindowAdapter() { 88 | override fun windowDestroyed(e: WindowEvent?) { 89 | animator.stop() 90 | System.exit(1) 91 | } 92 | }) 93 | } 94 | 95 | override fun init(drawable: GLAutoDrawable) { 96 | 97 | val gl = drawable.gl.gL4 98 | 99 | initDebug(gl) 100 | 101 | initBuffers(gl) 102 | 103 | initTexture(gl) 104 | 105 | initSampler(gl) 106 | 107 | initVertexArray(gl) 108 | 109 | program = Program(gl, this::class.java, "shaders/gl4", "hello-globe.vert", "hello-globe.frag") 110 | 111 | gl.glEnable(GL.GL_DEPTH_TEST) 112 | 113 | start = System.currentTimeMillis() 114 | } 115 | 116 | fun initDebug(gl: GL4) = with(gl) { 117 | 118 | window.context.addGLDebugListener(GlDebugOutput()) 119 | 120 | glDebugMessageControl( 121 | GL_DONT_CARE, 122 | GL_DONT_CARE, 123 | GL_DONT_CARE, 124 | 0, null, 125 | false) 126 | 127 | glDebugMessageControl( 128 | GL_DONT_CARE, 129 | GL_DONT_CARE, 130 | GL_DEBUG_SEVERITY_HIGH, 131 | 0, null, 132 | true) 133 | 134 | glDebugMessageControl( 135 | GL_DONT_CARE, 136 | GL_DONT_CARE, 137 | GL_DEBUG_SEVERITY_MEDIUM, 138 | 0, null, 139 | true) 140 | } 141 | 142 | fun initBuffers(gl: GL4) = with(gl) { 143 | 144 | val radius = 1f 145 | val rings = 100.s 146 | val sectors = 100.s 147 | 148 | val vertexBuffer = getVertexBuffer(radius, rings, sectors) 149 | val elementBuffer = getElementBuffer(radius, rings, sectors) 150 | 151 | elementCount = elementBuffer.capacity() 152 | 153 | glCreateBuffers(Buffer.MAX, bufferName) 154 | 155 | if (!bug1287) { 156 | 157 | glNamedBufferStorage(bufferName[Buffer.VERTEX], vertexBuffer.SIZE.L, vertexBuffer, GL_STATIC_DRAW) 158 | glNamedBufferStorage(bufferName[Buffer.ELEMENT], elementBuffer.SIZE.L, elementBuffer, GL_STATIC_DRAW) 159 | 160 | glNamedBufferStorage(bufferName[Buffer.GLOBAL_MATRICES], Mat4.SIZE * 2.L, null, GL_MAP_WRITE_BIT) 161 | glNamedBufferStorage(bufferName[Buffer.MODEL_MATRIX], Mat4.SIZE.L, null, GL_MAP_WRITE_BIT) 162 | 163 | } else { 164 | 165 | glBindBuffer(GL_ARRAY_BUFFER, bufferName[Buffer.VERTEX]) 166 | glBufferStorage(GL_ARRAY_BUFFER, vertexBuffer.SIZE.L, vertexBuffer, 0) 167 | glBindBuffer(GL_ARRAY_BUFFER, 0) 168 | 169 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferName[Buffer.ELEMENT]) 170 | glBufferStorage(GL_ELEMENT_ARRAY_BUFFER, elementBuffer.SIZE.L, elementBuffer, 0) 171 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) 172 | 173 | 174 | val uniformBufferOffset = intBufferBig(1) 175 | glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, uniformBufferOffset) 176 | val globalBlockSize = glm.max(Mat4.SIZE * 2, uniformBufferOffset[0]) 177 | val modelBlockSize = glm.max(Mat4.SIZE, uniformBufferOffset[0]) 178 | 179 | glBindBuffer(GL_UNIFORM_BUFFER, bufferName[Buffer.GLOBAL_MATRICES]) 180 | glBufferStorage(GL_UNIFORM_BUFFER, globalBlockSize.L, null, GL_MAP_WRITE_BIT or GL_MAP_PERSISTENT_BIT or GL_MAP_COHERENT_BIT) 181 | glBindBuffer(GL_UNIFORM_BUFFER, 0) 182 | 183 | glBindBuffer(GL_UNIFORM_BUFFER, bufferName[Buffer.MODEL_MATRIX]) 184 | glBufferStorage(GL_UNIFORM_BUFFER, modelBlockSize.L, null, GL_MAP_WRITE_BIT or GL_MAP_PERSISTENT_BIT or GL_MAP_COHERENT_BIT) 185 | glBindBuffer(GL_UNIFORM_BUFFER, 0) 186 | 187 | uniformBufferOffset.destroy() 188 | } 189 | 190 | destroyBuffers(vertexBuffer, elementBuffer) 191 | 192 | 193 | // map the transform buffers and keep them mapped 194 | globalMatricesPointer = glMapNamedBufferRange( 195 | bufferName[Buffer.GLOBAL_MATRICES], 196 | 0, 197 | Mat4.SIZE * 2.L, 198 | GL_MAP_WRITE_BIT or GL_MAP_PERSISTENT_BIT or GL_MAP_COHERENT_BIT or GL_MAP_INVALIDATE_BUFFER_BIT) 199 | 200 | modelMatrixPointer = glMapNamedBufferRange( 201 | bufferName[Buffer.MODEL_MATRIX], 202 | 0, 203 | Mat4.SIZE.L, 204 | GL_MAP_WRITE_BIT or GL_MAP_PERSISTENT_BIT or GL_MAP_COHERENT_BIT or GL_MAP_INVALIDATE_BUFFER_BIT) 205 | } 206 | 207 | fun getVertexBuffer(radius: Float, rings: Short, sectors: Short): FloatBuffer { 208 | 209 | val R = 1f / (rings - 1).toFloat() 210 | val S = 1f / (sectors - 1).toFloat() 211 | var r: Short = 0 212 | var s: Short 213 | var x: Float 214 | var y: Float 215 | var z: Float 216 | 217 | val vertexBuffer = floatBufferBig(rings.toInt() * sectors.toInt() * (3 + 2)) 218 | 219 | while (r < rings) { 220 | 221 | s = 0 222 | while (s < sectors) { 223 | 224 | x = glm.cos(2f * glm.pi.toFloat() * s.toFloat() * S) * glm.sin(glm.pi.toFloat() * r.toFloat() * R) 225 | y = glm.sin(-glm.pi.toFloat() / 2 + glm.pi.toFloat() * r.toFloat() * R) 226 | z = glm.sin(2f * glm.pi.toFloat() * s.toFloat() * S) * glm.sin(glm.pi.toFloat() * r.toFloat() * R) 227 | // positions 228 | vertexBuffer.put(x * radius) 229 | vertexBuffer.put(y * radius) 230 | vertexBuffer.put(z * radius) 231 | // texture coordinates 232 | vertexBuffer.put(1 - s * S) 233 | vertexBuffer.put(r * R) 234 | s++ 235 | } 236 | r++ 237 | } 238 | vertexBuffer.position(0) 239 | 240 | return vertexBuffer 241 | } 242 | 243 | fun getElementBuffer(radius: Float, rings: Short, sectors: Short): ShortBuffer { 244 | 245 | val R = 1f / (rings - 1).f 246 | val S = 1f / (sectors - 1).f 247 | var r = 0.s 248 | var s: Short 249 | val x: Float 250 | val y: Float 251 | val z: Float 252 | 253 | val elementBuffer = shortBufferBig(rings.i * sectors.i * 6) 254 | 255 | while (r < rings - 1) { 256 | 257 | s = 0 258 | while (s < sectors - 1) { 259 | 260 | elementBuffer.put((r * sectors + s).s) 261 | elementBuffer.put((r * sectors + (s + 1)).s) 262 | elementBuffer.put(((r + 1) * sectors + (s + 1)).s) 263 | elementBuffer.put(((r + 1) * sectors + (s + 1)).s) 264 | elementBuffer.put((r * sectors + s).s) 265 | // elementBuffer.put((short) (r * sectors + (s + 1))); 266 | elementBuffer.put(((r + 1) * sectors + s).s) 267 | s++ 268 | } 269 | r++ 270 | } 271 | elementBuffer.position(0) 272 | 273 | return elementBuffer 274 | } 275 | 276 | fun initVertexArray(gl: GL4) = with(gl) { 277 | 278 | glCreateVertexArrays(1, vertexArrayName) 279 | 280 | glVertexArrayAttribBinding(vertexArrayName[0], Semantic.Attr.POSITION, Semantic.Stream.A) 281 | glVertexArrayAttribBinding(vertexArrayName[0], Semantic.Attr.TEXCOORD, Semantic.Stream.A) 282 | 283 | glVertexArrayAttribFormat(vertexArrayName[0], Semantic.Attr.POSITION, Vec3.length, GL_FLOAT, false, 0) 284 | glVertexArrayAttribFormat(vertexArrayName[0], Semantic.Attr.TEXCOORD, Vec2.length, GL_FLOAT, false, Vec3.SIZE) 285 | 286 | glEnableVertexArrayAttrib(vertexArrayName[0], Semantic.Attr.POSITION) 287 | glEnableVertexArrayAttrib(vertexArrayName[0], Semantic.Attr.TEXCOORD) 288 | 289 | glVertexArrayElementBuffer(vertexArrayName[0], bufferName[Buffer.ELEMENT]) 290 | 291 | glVertexArrayVertexBuffer(vertexArrayName[0], Semantic.Stream.A, bufferName[Buffer.VERTEX], 0, Vec2.SIZE + Vec3.SIZE) 292 | } 293 | 294 | fun initTexture(gl: GL4) = with(gl) { 295 | 296 | val texture = this::class.java.classLoader.getResource("images/globe.png") 297 | 298 | val textureData = TextureIO.newTextureData(glProfile, texture!!, false, TextureIO.PNG) 299 | 300 | glCreateTextures(GL_TEXTURE_2D, 1, textureName) 301 | 302 | glTextureParameteri(textureName[0], GL_TEXTURE_BASE_LEVEL, 0) 303 | glTextureParameteri(textureName[0], GL_TEXTURE_MAX_LEVEL, 0) 304 | 305 | glTextureStorage2D(textureName[0], 306 | 1, // level 307 | textureData.internalFormat, 308 | textureData.width, textureData.height) 309 | 310 | glTextureSubImage2D(textureName.get(0), 311 | 0, // level 312 | 0, 0, // offset 313 | textureData.width, textureData.height, 314 | textureData.pixelFormat, textureData.pixelType, 315 | textureData.buffer) 316 | } 317 | 318 | fun initSampler(gl: GL4) = with(gl) { 319 | 320 | glGenSamplers(1, samplerName) 321 | 322 | glSamplerParameteri(samplerName[0], GL_TEXTURE_MAG_FILTER, GL_NEAREST) 323 | glSamplerParameteri(samplerName[0], GL_TEXTURE_MIN_FILTER, GL_NEAREST) 324 | 325 | glSamplerParameteri(samplerName[0], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) 326 | glSamplerParameteri(samplerName[0], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) 327 | } 328 | 329 | override fun display(drawable: GLAutoDrawable) = with(drawable.gl.gL4) { 330 | 331 | // view matrix 332 | run { 333 | val view = glm.lookAt(Vec3(0f, 0f, 3f), Vec3(), Vec3(0f, 1f, 0f)) 334 | view.to(globalMatricesPointer, Mat4.SIZE) 335 | } 336 | 337 | glClearBufferfv(GL_COLOR, 0, clearColor.put(1f, .5f, 0f, 1f)) 338 | glClearBufferfv(GL_DEPTH, 0, clearDepth.put(0, 1f)) 339 | 340 | 341 | // model matrix 342 | run { 343 | val now = System.currentTimeMillis() 344 | val diff = (now - start).f / 1_000f 345 | 346 | val model = Mat4().rotate_(-diff, 0f, 1f, 0f) 347 | model to modelMatrixPointer 348 | } 349 | 350 | glUseProgram(program.name) 351 | glBindVertexArray(vertexArrayName[0]) 352 | 353 | glBindBufferBase( 354 | GL_UNIFORM_BUFFER, 355 | Semantic.Uniform.TRANSFORM0, 356 | bufferName[Buffer.GLOBAL_MATRICES]) 357 | 358 | glBindBufferBase( 359 | GL_UNIFORM_BUFFER, 360 | Semantic.Uniform.TRANSFORM1, 361 | bufferName[Buffer.MODEL_MATRIX]) 362 | 363 | glBindTextureUnit( 364 | Semantic.Sampler.DIFFUSE, 365 | textureName[0]) 366 | glBindSampler(Semantic.Sampler.DIFFUSE, samplerName[0]) 367 | 368 | glDrawElements( 369 | GL.GL_TRIANGLES, 370 | elementCount, 371 | GL_UNSIGNED_SHORT, 372 | 0) 373 | } 374 | 375 | override fun reshape(drawable: GLAutoDrawable, x: Int, y: Int, width: Int, height: Int) { 376 | 377 | val gl = drawable.gl.gL4 378 | 379 | val aspect = width.f / height 380 | 381 | val proj = glm.perspective(glm.pi.f * 0.25f, aspect, 0.1f, 100f) 382 | proj to globalMatricesPointer 383 | } 384 | 385 | override fun dispose(drawable: GLAutoDrawable) = with(drawable.gl.gL4) { 386 | 387 | glUnmapNamedBuffer(bufferName[Buffer.GLOBAL_MATRICES]) 388 | glUnmapNamedBuffer(bufferName[Buffer.MODEL_MATRIX]) 389 | 390 | glDeleteProgram(program.name) 391 | glDeleteVertexArrays(1, vertexArrayName) 392 | glDeleteBuffers(Buffer.MAX, bufferName) 393 | glDeleteTextures(1, textureName) 394 | glDeleteSamplers(1, samplerName) 395 | 396 | destroyBuffers(vertexArrayName, bufferName, textureName, samplerName, clearColor, clearDepth) 397 | } 398 | 399 | override fun keyPressed(e: KeyEvent) { 400 | if (e.keyCode == KeyEvent.VK_ESCAPE) { 401 | Thread { window.destroy() }.start() 402 | } 403 | } 404 | 405 | override fun keyReleased(e: KeyEvent) {} 406 | } -------------------------------------------------------------------------------- /src/main/java/gl4/HelloGlobe.java: -------------------------------------------------------------------------------- 1 | 2 | package gl4; 3 | 4 | import com.jogamp.newt.event.KeyEvent; 5 | import com.jogamp.newt.event.KeyListener; 6 | import com.jogamp.newt.event.WindowAdapter; 7 | import com.jogamp.newt.event.WindowEvent; 8 | import com.jogamp.newt.opengl.GLWindow; 9 | import com.jogamp.opengl.*; 10 | import com.jogamp.opengl.util.Animator; 11 | import com.jogamp.opengl.util.GLBuffers; 12 | import com.jogamp.opengl.util.texture.TextureData; 13 | import com.jogamp.opengl.util.texture.TextureIO; 14 | import framework.Semantic; 15 | import glm.mat.Mat4x4; 16 | import glm.vec._2.Vec2; 17 | import glm.vec._3.Vec3; 18 | import uno.debug.GlDebugOutput; 19 | import uno.glsl.Program; 20 | 21 | import java.io.IOException; 22 | import java.net.URL; 23 | import java.nio.ByteBuffer; 24 | import java.nio.FloatBuffer; 25 | import java.nio.IntBuffer; 26 | import java.nio.ShortBuffer; 27 | import java.util.logging.Level; 28 | import java.util.logging.Logger; 29 | 30 | import static com.jogamp.opengl.GL.GL_DONT_CARE; 31 | import static com.jogamp.opengl.GL.GL_FLOAT; 32 | import static com.jogamp.opengl.GL.GL_MAP_INVALIDATE_BUFFER_BIT; 33 | import static com.jogamp.opengl.GL.GL_MAP_WRITE_BIT; 34 | import static com.jogamp.opengl.GL2ES2.GL_DEBUG_SEVERITY_HIGH; 35 | import static com.jogamp.opengl.GL2ES2.GL_DEBUG_SEVERITY_MEDIUM; 36 | import static com.jogamp.opengl.GL2ES3.GL_UNIFORM_BUFFER; 37 | import static com.jogamp.opengl.GL2ES3.GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT; 38 | import static com.jogamp.opengl.GL4.GL_ARRAY_BUFFER; 39 | import static com.jogamp.opengl.GL4.GL_CLAMP_TO_EDGE; 40 | import static com.jogamp.opengl.GL4.*; 41 | import static com.jogamp.opengl.GL4.GL_DEPTH_TEST; 42 | import static com.jogamp.opengl.GL4.GL_ELEMENT_ARRAY_BUFFER; 43 | import static com.jogamp.opengl.GL4.GL_NEAREST; 44 | import static com.jogamp.opengl.GL4.GL_STATIC_DRAW; 45 | import static com.jogamp.opengl.GL4.GL_TEXTURE_2D; 46 | import static com.jogamp.opengl.GL4.GL_TEXTURE_MAG_FILTER; 47 | import static com.jogamp.opengl.GL4.GL_TEXTURE_MIN_FILTER; 48 | import static com.jogamp.opengl.GL4.GL_TEXTURE_WRAP_S; 49 | import static com.jogamp.opengl.GL4.GL_TEXTURE_WRAP_T; 50 | import static com.jogamp.opengl.GL4.GL_TRIANGLES; 51 | import static com.jogamp.opengl.GL4.GL_UNSIGNED_SHORT; 52 | import static glm.GlmKt.glm; 53 | import static uno.buffer.UtilKt.destroyBuffer; 54 | import static uno.buffer.UtilKt.destroyBuffers; 55 | 56 | /** 57 | * @author elect 58 | */ 59 | public class HelloGlobe implements GLEventListener, KeyListener { 60 | 61 | private static GLWindow window; 62 | private static Animator animator; 63 | 64 | public static void main(String[] args) { 65 | new HelloGlobe().setup(); 66 | } 67 | 68 | private interface Buffer { 69 | 70 | int VERTEX = 0; 71 | int ELEMENT = 1; 72 | int GLOBAL_MATRICES = 2; 73 | int MODEL_MATRIX = 3; 74 | int MAX = 4; 75 | } 76 | 77 | private IntBuffer bufferName = GLBuffers.newDirectIntBuffer(Buffer.MAX); 78 | private IntBuffer vertexArrayName = GLBuffers.newDirectIntBuffer(1); 79 | 80 | private IntBuffer textureName = GLBuffers.newDirectIntBuffer(1); 81 | private IntBuffer samplerName = GLBuffers.newDirectIntBuffer(1); 82 | 83 | private FloatBuffer clearColor = GLBuffers.newDirectFloatBuffer(4); 84 | private FloatBuffer clearDepth = GLBuffers.newDirectFloatBuffer(1); 85 | 86 | private ByteBuffer globalMatricesPointer, modelMatrixPointer; 87 | // https://jogamp.org/bugzilla/show_bug.cgi?id=1287 88 | private boolean bug1287 = true; 89 | 90 | private Program program; 91 | 92 | private long start; 93 | 94 | private int elementCount; 95 | 96 | private void setup() { 97 | 98 | GLProfile glProfile = GLProfile.get(GLProfile.GL3); 99 | GLCapabilities glCapabilities = new GLCapabilities(glProfile); 100 | 101 | window = GLWindow.create(glCapabilities); 102 | 103 | window.setTitle("Hello Globe"); 104 | window.setSize(1024, 768); 105 | 106 | window.setContextCreationFlags(GLContext.CTX_OPTION_DEBUG); 107 | window.setVisible(true); 108 | 109 | window.addGLEventListener(this); 110 | window.addKeyListener(this); 111 | 112 | animator = new Animator(window); 113 | animator.start(); 114 | 115 | window.addWindowListener(new WindowAdapter() { 116 | @Override 117 | public void windowDestroyed(WindowEvent e) { 118 | animator.stop(); 119 | System.exit(1); 120 | } 121 | }); 122 | } 123 | 124 | @Override 125 | public void init(GLAutoDrawable drawable) { 126 | 127 | GL4 gl = drawable.getGL().getGL4(); 128 | 129 | initDebug(gl); 130 | 131 | initBuffers(gl); 132 | 133 | initTexture(gl); 134 | 135 | initSampler(gl); 136 | 137 | initVertexArray(gl); 138 | 139 | program = new Program(gl, getClass(), "shaders/gl4", "hello-globe.vert", "hello-globe.frag"); 140 | 141 | gl.glEnable(GL_DEPTH_TEST); 142 | 143 | start = System.currentTimeMillis(); 144 | } 145 | 146 | private void initDebug(GL4 gl) { 147 | 148 | window.getContext().addGLDebugListener(new GlDebugOutput()); 149 | 150 | gl.glDebugMessageControl( 151 | GL_DONT_CARE, 152 | GL_DONT_CARE, 153 | GL_DONT_CARE, 154 | 0, 155 | null, 156 | false); 157 | 158 | gl.glDebugMessageControl( 159 | GL_DONT_CARE, 160 | GL_DONT_CARE, 161 | GL_DEBUG_SEVERITY_HIGH, 162 | 0, 163 | null, 164 | true); 165 | 166 | gl.glDebugMessageControl( 167 | GL_DONT_CARE, 168 | GL_DONT_CARE, 169 | GL_DEBUG_SEVERITY_MEDIUM, 170 | 0, 171 | null, 172 | true); 173 | } 174 | 175 | private void initBuffers(GL4 gl) { 176 | 177 | float radius = 1f; 178 | short rings = 100; 179 | short sectors = 100; 180 | 181 | FloatBuffer vertexBuffer = getVertexBuffer(radius, rings, sectors); 182 | ShortBuffer elementBuffer = getElementBuffer(radius, rings, sectors); 183 | 184 | elementCount = elementBuffer.capacity(); 185 | 186 | gl.glCreateBuffers(Buffer.MAX, bufferName); 187 | 188 | if (!bug1287) { 189 | 190 | gl.glNamedBufferStorage(bufferName.get(Buffer.VERTEX), vertexBuffer.capacity() * Float.BYTES, vertexBuffer, 191 | GL_STATIC_DRAW); 192 | gl.glNamedBufferStorage(bufferName.get(Buffer.ELEMENT), elementBuffer.capacity() * Short.BYTES, 193 | elementBuffer, GL_STATIC_DRAW); 194 | 195 | gl.glNamedBufferStorage(bufferName.get(Buffer.GLOBAL_MATRICES), Mat4x4.SIZE * 2, null, GL_MAP_WRITE_BIT); 196 | gl.glNamedBufferStorage(bufferName.get(Buffer.MODEL_MATRIX), Mat4x4.SIZE, null, GL_MAP_WRITE_BIT); 197 | 198 | } else { 199 | 200 | gl.glBindBuffer(GL_ARRAY_BUFFER, bufferName.get(Buffer.VERTEX)); 201 | gl.glBufferStorage(GL_ARRAY_BUFFER, vertexBuffer.capacity() * Float.BYTES, vertexBuffer, 0); 202 | gl.glBindBuffer(GL_ARRAY_BUFFER, 0); 203 | 204 | gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferName.get(Buffer.ELEMENT)); 205 | gl.glBufferStorage(GL_ELEMENT_ARRAY_BUFFER, elementBuffer.capacity() * Short.BYTES, elementBuffer, 0); 206 | gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 207 | 208 | 209 | IntBuffer uniformBufferOffset = GLBuffers.newDirectIntBuffer(1); 210 | gl.glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, uniformBufferOffset); 211 | int globalBlockSize = glm.max(Mat4x4.SIZE * 2, uniformBufferOffset.get(0)); 212 | int modelBlockSize = glm.max(Mat4x4.SIZE, uniformBufferOffset.get(0)); 213 | 214 | gl.glBindBuffer(GL_UNIFORM_BUFFER, bufferName.get(Buffer.GLOBAL_MATRICES)); 215 | gl.glBufferStorage(GL_UNIFORM_BUFFER, globalBlockSize, null, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); 216 | gl.glBindBuffer(GL_UNIFORM_BUFFER, 0); 217 | 218 | gl.glBindBuffer(GL_UNIFORM_BUFFER, bufferName.get(Buffer.MODEL_MATRIX)); 219 | gl.glBufferStorage(GL_UNIFORM_BUFFER, modelBlockSize, null, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); 220 | gl.glBindBuffer(GL_UNIFORM_BUFFER, 0); 221 | 222 | destroyBuffer(uniformBufferOffset); 223 | } 224 | 225 | destroyBuffers(vertexBuffer, elementBuffer); 226 | 227 | 228 | // map the transform buffers and keep them mapped 229 | globalMatricesPointer = gl.glMapNamedBufferRange( 230 | bufferName.get(Buffer.GLOBAL_MATRICES), 231 | 0, 232 | Mat4x4.SIZE * 2, 233 | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); 234 | 235 | modelMatrixPointer = gl.glMapNamedBufferRange( 236 | bufferName.get(Buffer.MODEL_MATRIX), 237 | 0, 238 | Mat4x4.SIZE, 239 | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); 240 | } 241 | 242 | private FloatBuffer getVertexBuffer(float radius, short rings, short sectors) { 243 | 244 | float R = 1f / (float) (rings - 1); 245 | float S = 1f / (float) (sectors - 1); 246 | short r, s; 247 | float x, y, z; 248 | 249 | FloatBuffer vertexBuffer = GLBuffers.newDirectFloatBuffer(rings * sectors * (3 + 2)); 250 | 251 | for (r = 0; r < rings; r++) { 252 | 253 | for (s = 0; s < sectors; s++) { 254 | 255 | x = glm.cos(2 * (float) glm.pi * s * S) * glm.sin((float) glm.pi * r * R); 256 | y = glm.sin(-(float) glm.pi / 2 + (float) glm.pi * r * R); 257 | z = glm.sin(2 * (float) glm.pi * s * S) * glm.sin((float) glm.pi * r * R); 258 | // positions 259 | vertexBuffer.put(x * radius); 260 | vertexBuffer.put(y * radius); 261 | vertexBuffer.put(z * radius); 262 | // texture coordinates 263 | vertexBuffer.put(1 - s * S); 264 | vertexBuffer.put(r * R); 265 | } 266 | } 267 | vertexBuffer.position(0); 268 | 269 | return vertexBuffer; 270 | } 271 | 272 | private ShortBuffer getElementBuffer(float radius, short rings, short sectors) { 273 | 274 | float R = 1f / (float) (rings - 1); 275 | float S = 1f / (float) (sectors - 1); 276 | short r, s; 277 | float x, y, z; 278 | 279 | ShortBuffer elementBuffer = GLBuffers.newDirectShortBuffer(rings * sectors * 6); 280 | 281 | for (r = 0; r < rings - 1; r++) { 282 | 283 | for (s = 0; s < sectors - 1; s++) { 284 | 285 | elementBuffer.put((short) (r * sectors + s)); 286 | elementBuffer.put((short) (r * sectors + (s + 1))); 287 | elementBuffer.put((short) ((r + 1) * sectors + (s + 1))); 288 | elementBuffer.put((short) ((r + 1) * sectors + (s + 1))); 289 | elementBuffer.put((short) (r * sectors + s)); 290 | // elementBuffer.put((short) (r * sectors + (s + 1))); 291 | elementBuffer.put((short) ((r + 1) * sectors + s)); 292 | } 293 | } 294 | elementBuffer.position(0); 295 | 296 | return elementBuffer; 297 | } 298 | 299 | private void initVertexArray(GL4 gl) { 300 | 301 | gl.glCreateVertexArrays(1, vertexArrayName); 302 | 303 | gl.glVertexArrayAttribBinding(vertexArrayName.get(0), Semantic.Attr.POSITION, Semantic.Stream.A); 304 | gl.glVertexArrayAttribBinding(vertexArrayName.get(0), Semantic.Attr.TEXCOORD, Semantic.Stream.A); 305 | 306 | gl.glVertexArrayAttribFormat(vertexArrayName.get(0), Semantic.Attr.POSITION, Vec3.length, GL_FLOAT, false, 0); 307 | gl.glVertexArrayAttribFormat(vertexArrayName.get(0), Semantic.Attr.TEXCOORD, Vec2.length, GL_FLOAT, false, Vec3.SIZE); 308 | 309 | gl.glEnableVertexArrayAttrib(vertexArrayName.get(0), Semantic.Attr.POSITION); 310 | gl.glEnableVertexArrayAttrib(vertexArrayName.get(0), Semantic.Attr.TEXCOORD); 311 | 312 | gl.glVertexArrayElementBuffer(vertexArrayName.get(0), bufferName.get(Buffer.ELEMENT)); 313 | 314 | gl.glVertexArrayVertexBuffer(vertexArrayName.get(0), Semantic.Stream.A, bufferName.get(Buffer.VERTEX), 0, Vec2.SIZE + Vec3.SIZE); 315 | } 316 | 317 | private void initTexture(GL4 gl) { 318 | 319 | try { 320 | URL texture = getClass().getClassLoader().getResource("images/globe.png"); 321 | 322 | TextureData textureData = TextureIO.newTextureData(gl.getGLProfile(), texture, false, TextureIO.PNG); 323 | 324 | gl.glCreateTextures(GL_TEXTURE_2D, 1, textureName); 325 | 326 | gl.glTextureParameteri(textureName.get(0), GL_TEXTURE_BASE_LEVEL, 0); 327 | gl.glTextureParameteri(textureName.get(0), GL_TEXTURE_MAX_LEVEL, 0); 328 | 329 | gl.glTextureStorage2D(textureName.get(0), 330 | 1, // level 331 | textureData.getInternalFormat(), 332 | textureData.getWidth(), textureData.getHeight()); 333 | 334 | gl.glTextureSubImage2D(textureName.get(0), 335 | 0, // level 336 | 0, 0, // offset 337 | textureData.getWidth(), textureData.getHeight(), 338 | textureData.getPixelFormat(), textureData.getPixelType(), 339 | textureData.getBuffer()); 340 | 341 | } catch (IOException ex) { 342 | Logger.getLogger(HelloGlobe.class.getName()).log(Level.SEVERE, null, ex); 343 | } 344 | } 345 | 346 | private void initSampler(GL4 gl) { 347 | 348 | gl.glGenSamplers(1, samplerName); 349 | 350 | gl.glSamplerParameteri(samplerName.get(0), GL_TEXTURE_MAG_FILTER, GL_NEAREST); 351 | gl.glSamplerParameteri(samplerName.get(0), GL_TEXTURE_MIN_FILTER, GL_NEAREST); 352 | 353 | gl.glSamplerParameteri(samplerName.get(0), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 354 | gl.glSamplerParameteri(samplerName.get(0), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 355 | } 356 | 357 | @Override 358 | public void display(GLAutoDrawable drawable) { 359 | 360 | GL4 gl = drawable.getGL().getGL4(); 361 | 362 | // view matrix 363 | { 364 | Mat4x4 view = glm.lookAt(new Vec3(0, 0, 3), new Vec3(), new Vec3(0, 1, 0)); 365 | view.to(globalMatricesPointer, Mat4x4.SIZE); 366 | } 367 | 368 | gl.glClearBufferfv(GL_COLOR, 0, clearColor.put(0, 1f).put(1, .5f).put(2, 0f).put(3, 1f)); 369 | gl.glClearBufferfv(GL_DEPTH, 0, clearDepth.put(0, 1f)); 370 | 371 | 372 | // model matrix 373 | { 374 | long now = System.currentTimeMillis(); 375 | float diff = (float) (now - start) / 1_000f; 376 | 377 | Mat4x4 model = new Mat4x4().rotate_(-diff, 0f, 1f, 0f); 378 | model.to(modelMatrixPointer); 379 | } 380 | 381 | gl.glUseProgram(program.name); 382 | gl.glBindVertexArray(vertexArrayName.get(0)); 383 | 384 | gl.glBindBufferBase( 385 | GL_UNIFORM_BUFFER, 386 | Semantic.Uniform.TRANSFORM0, 387 | bufferName.get(Buffer.GLOBAL_MATRICES)); 388 | 389 | gl.glBindBufferBase( 390 | GL_UNIFORM_BUFFER, 391 | Semantic.Uniform.TRANSFORM1, 392 | bufferName.get(Buffer.MODEL_MATRIX)); 393 | 394 | gl.glBindTextureUnit( 395 | Semantic.Sampler.DIFFUSE, 396 | textureName.get(0)); 397 | gl.glBindSampler(Semantic.Sampler.DIFFUSE, samplerName.get(0)); 398 | 399 | gl.glDrawElements( 400 | GL_TRIANGLES, 401 | elementCount, 402 | GL_UNSIGNED_SHORT, 403 | 0); 404 | } 405 | 406 | @Override 407 | public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { 408 | 409 | GL4 gl = drawable.getGL().getGL4(); 410 | 411 | float aspect = (float) width / height; 412 | 413 | Mat4x4 proj = glm.perspective((float) glm.pi * 0.25f, aspect, 0.1f, 100f); 414 | proj.to(globalMatricesPointer); 415 | } 416 | 417 | @Override 418 | public void dispose(GLAutoDrawable drawable) { 419 | 420 | GL4 gl = drawable.getGL().getGL4(); 421 | 422 | gl.glUnmapNamedBuffer(bufferName.get(Buffer.GLOBAL_MATRICES)); 423 | gl.glUnmapNamedBuffer(bufferName.get(Buffer.MODEL_MATRIX)); 424 | 425 | gl.glDeleteProgram(program.name); 426 | gl.glDeleteVertexArrays(1, vertexArrayName); 427 | gl.glDeleteBuffers(Buffer.MAX, bufferName); 428 | gl.glDeleteTextures(1, textureName); 429 | gl.glDeleteSamplers(1, samplerName); 430 | 431 | destroyBuffers(vertexArrayName, bufferName, textureName, samplerName, clearColor, clearDepth); 432 | } 433 | 434 | @Override 435 | public void keyPressed(KeyEvent e) { 436 | if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { 437 | new Thread(() -> { 438 | window.destroy(); 439 | }).start(); 440 | } 441 | } 442 | 443 | @Override 444 | public void keyReleased(KeyEvent e) { 445 | 446 | } 447 | } --------------------------------------------------------------------------------