From fb0b9bc4c9e562d4389e5abe250f60e53d1fbe93 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sat, 8 Jul 2023 22:03:41 -0700 Subject: [PATCH 01/13] rust core natives Signed-off-by: Michael Pollind --- build.gradle | 14 +++++++++++ engine/build.gradle | 2 ++ .../core/subsystem/lwjgl/LwjglGraphics.java | 25 +++++++++++++++---- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 51cef4f4a21..739fa9c7a80 100644 --- a/build.gradle +++ b/build.gradle @@ -79,6 +79,7 @@ ext { subDirLibs = 'libs' LwjglVersion = '3.3.1' + rustCoreVersion = '0.0.1' } @@ -114,6 +115,9 @@ dependencies { // Natives for JNBullet natives group: 'org.terasology.jnbullet', name: 'JNBullet', version: '1.0.2', ext: 'zip' + // Natives for core + natives group: 'org.terasology.rust', name: 'core', version: rustCoreVersion, ext: 'zip' + } task extractWindowsNatives(type: Copy) { @@ -160,6 +164,15 @@ task extractNativeBulletNatives(type: Copy) { } +task extractRustCoreNatives(type:Copy) { + description = "Extracts the JNBullet natives from the downloaded zip" + from { + configurations.natives.collect { it.getName().contains('core') ? zipTree(it) : [] } + } + into ("$dirNatives") +} + + task extractNatives { description = "Extracts all the native lwjgl libraries from the downloaded zip" dependsOn extractWindowsNatives @@ -167,6 +180,7 @@ task extractNatives { dependsOn extractMacOSXNatives dependsOn extractJNLuaNatives dependsOn extractNativeBulletNatives + dependsOn extractRustCoreNatives } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/engine/build.gradle b/engine/build.gradle index e10ec9d3b40..1aa40c4fbbe 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -8,6 +8,7 @@ plugins { id "org.jetbrains.gradle.plugin.idea-ext" id "com.google.protobuf" id "terasology-common" + } // Grab all the common stuff like plugins to use, artifact repositories, code analysis config, etc @@ -150,6 +151,7 @@ dependencies { api group: 'org.terasology.nui', name: 'nui-reflect', version: '3.0.0' api group: 'org.terasology.nui', name: 'nui-gestalt7', version: '3.0.0' + api group: 'org.terasology.rust', name: 'core', version: rustCoreVersion // Wildcard dependency to catch any libs provided with the project (remote repo preferred instead) api fileTree(dir: 'libs', include: '*.jar') diff --git a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java index e17063912c1..a44b90d6eca 100644 --- a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java +++ b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java @@ -5,6 +5,7 @@ import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFWFramebufferSizeCallback; import org.lwjgl.glfw.GLFWImage; +import org.lwjgl.glfw.GLFWNativeX11; import org.lwjgl.opengl.GL43; import org.lwjgl.system.MemoryUtil; import org.slf4j.Logger; @@ -18,6 +19,7 @@ import org.terasology.engine.rendering.ShaderManager; import org.terasology.engine.rendering.ShaderManagerLwjgl; import org.terasology.engine.rendering.nui.internal.LwjglCanvasRenderer; +import org.terasology.engine.rust.TeraRusty; import org.terasology.engine.utilities.OS; import org.terasology.gestalt.assets.module.ModuleAwareAssetTypeManager; import org.terasology.nui.canvas.CanvasRenderer; @@ -140,19 +142,32 @@ private void initWindow() { logger.info("Initializing display (if last line in log then likely the game crashed from an issue with your " + "video card)"); - // set opengl core profile to 3.3 - GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 3); - GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 3); - GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE); - long window = GLFW.glfwCreateWindow( config.getWindowWidth(), config.getWindowHeight(), "Terasology Alpha", 0, 0); + +// GLFWNativeX11.glfwGetX11Window(window) + switch(GLFW.glfwGetPlatform()) { + case GLFW.GLFW_PLATFORM_X11: + TeraRusty.initializeWindowX11(GLFWNativeX11.glfwGetX11Display(), + GLFWNativeX11.glfwGetX11Window(window)); + break; + case GLFW.GLFW_PLATFORM_WAYLAND: + break; + case GLFW.GLFW_PLATFORM_WIN32: + break; + case GLFW.GLFW_PLATFORM_COCOA: + break; + default: + break; + } + if (window == 0) { throw new RuntimeException("Failed to create window"); } GLFW.glfwMakeContextCurrent(window); + if (!config.isVSync()) { GLFW.glfwSwapInterval(0); } From ea69738ba2ca910f2e23670f2959d615749c1bb5 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sun, 9 Jul 2023 20:03:39 -0700 Subject: [PATCH 02/13] rough working implemention of wgpu Signed-off-by: Michael Pollind --- build.gradle | 9 +- .../subsystem/lwjgl/LwjglDisplayDevice.java | 31 +- .../core/subsystem/lwjgl/LwjglGraphics.java | 50 +- .../subsystem/lwjgl/LwjglGraphicsManager.java | 102 ++-- .../subsystem/lwjgl/LwjglGraphicsUtil.java | 67 --- .../core/subsystem/lwjgl/LwjglInput.java | 6 +- .../engine/input/lwjgl/LwjglMouseDevice.java | 7 +- .../engine/rendering/opengl/GLSLMaterial.java | 503 +++++++++--------- .../engine/rendering/opengl/GLSLShader.java | 72 +-- .../engine/rendering/opengl/OpenGLMesh.java | 64 +-- .../rendering/opengl/OpenGLTexture.java | 144 ++--- .../rendering/world/WorldRendererImpl.java | 2 +- 12 files changed, 477 insertions(+), 580 deletions(-) diff --git a/build.gradle b/build.gradle index 739fa9c7a80..05d8101c0d5 100644 --- a/build.gradle +++ b/build.gradle @@ -116,7 +116,9 @@ dependencies { natives group: 'org.terasology.jnbullet', name: 'JNBullet', version: '1.0.2', ext: 'zip' // Natives for core - natives group: 'org.terasology.rust', name: 'core', version: rustCoreVersion, ext: 'zip' + natives(group: 'org.terasology.rust', name: 'core-rust', version: rustCoreVersion){ + transitive = true + } } @@ -163,16 +165,17 @@ task extractNativeBulletNatives(type: Copy) { into("$dirNatives") } - task extractRustCoreNatives(type:Copy) { description = "Extracts the JNBullet natives from the downloaded zip" + from configurations.natives from { - configurations.natives.collect { it.getName().contains('core') ? zipTree(it) : [] } + configurations.natives.collect { it.getName().contains('core-rust') ? zipTree(it) : [] } } into ("$dirNatives") } + task extractNatives { description = "Extracts all the native lwjgl libraries from the downloaded zip" dependsOn extractWindowsNatives diff --git a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglDisplayDevice.java b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglDisplayDevice.java index dda04be1427..8b95d3a146e 100644 --- a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglDisplayDevice.java +++ b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglDisplayDevice.java @@ -46,17 +46,17 @@ public LwjglDisplayDevice(Context context) { @Override public boolean hasFocus() { - return GLFW.GLFW_TRUE == GLFW.glfwGetWindowAttrib(GLFW.glfwGetCurrentContext(), GLFW.GLFW_FOCUSED); + return GLFW.GLFW_TRUE == GLFW.glfwGetWindowAttrib(LwjglGraphics.primaryWindow, GLFW.GLFW_FOCUSED); } @Override public boolean isCloseRequested() { - return GLFW.glfwWindowShouldClose(GLFW.glfwGetCurrentContext()); + return GLFW.glfwWindowShouldClose(LwjglGraphics.primaryWindow); } @Override public boolean isFullscreen() { - return MemoryUtil.NULL != GLFW.glfwGetWindowMonitor(GLFW.glfwGetCurrentContext()); + return MemoryUtil.NULL != GLFW.glfwGetWindowMonitor(LwjglGraphics.primaryWindow); } @Override @@ -79,7 +79,7 @@ public void setDisplayModeSetting(DisplayModeSetting displayModeSetting) { } public void setDisplayModeSetting(DisplayModeSetting displayModeSetting, boolean resize) { - long window = GLFW.glfwGetCurrentContext(); +// long window = GLFW.glfwGetCurrentContext(); switch (displayModeSetting) { case FULLSCREEN: updateFullScreenDisplay(); @@ -88,21 +88,21 @@ public void setDisplayModeSetting(DisplayModeSetting displayModeSetting, boolean break; case WINDOWED_FULLSCREEN: GLFWVidMode vidMode = desktopResolution.get(); - GLFW.glfwSetWindowMonitor(window, + GLFW.glfwSetWindowMonitor(LwjglGraphics.primaryWindow, MemoryUtil.NULL, 0, 0, vidMode.width(), vidMode.height(), GLFW.GLFW_DONT_CARE); - GLFW.glfwSetWindowAttrib(window, GLFW.GLFW_DECORATED, GLFW.GLFW_FALSE); + GLFW.glfwSetWindowAttrib(LwjglGraphics.primaryWindow, GLFW.GLFW_DECORATED, GLFW.GLFW_FALSE); config.setDisplayModeSetting(displayModeSetting); config.setWindowedFullscreen(true); break; case WINDOWED: - GLFW.glfwSetWindowAttrib(window, GLFW.GLFW_DECORATED, GLFW.GLFW_TRUE); - GLFW.glfwSetWindowAttrib(window, GLFW.GLFW_RESIZABLE, GLFW.GLFW_TRUE); - GLFW.glfwSetWindowMonitor(window, + GLFW.glfwSetWindowAttrib(LwjglGraphics.primaryWindow, GLFW.GLFW_DECORATED, GLFW.GLFW_TRUE); + GLFW.glfwSetWindowAttrib(LwjglGraphics.primaryWindow, GLFW.GLFW_RESIZABLE, GLFW.GLFW_TRUE); + GLFW.glfwSetWindowMonitor(LwjglGraphics.primaryWindow, MemoryUtil.NULL, config.getWindowPosX(), config.getWindowPosY(), @@ -150,7 +150,7 @@ private void updateWindow() { if (isWindowDirty) { int[] windowWidth = new int[1]; int[] windowHeight = new int[1]; - GLFW.glfwGetWindowSize(GLFW.glfwGetCurrentContext(), windowWidth, windowHeight); + GLFW.glfwGetWindowSize(LwjglGraphics.primaryWindow, windowWidth, windowHeight); this.windowWidth = windowWidth[0]; this.windowHeight = windowHeight[0]; isWindowDirty = false; @@ -183,13 +183,13 @@ public void prepareToRender() { @Override public DisplayDeviceInfo getInfo() { - LwjglGraphicsUtil.updateDisplayDeviceInfo(displayDeviceInfo); +// LwjglGraphicsUtil.updateDisplayDeviceInfo(displayDeviceInfo); return displayDeviceInfo; } public void update() { processMessages(); - GLFW.glfwSwapBuffers(GLFW.glfwGetCurrentContext()); +// GLFW.glfwSwapBuffers(GLFW.glfwGetCurrentContext()); isWindowDirty = true; } @@ -199,10 +199,10 @@ private void updateViewport() { } protected void updateViewport(int width, int height) { - glViewport(0, 0, width, height); +// glViewport(0, 0, width, height); //If the screen is minimized, resolution change is stopped to avoid the width and height of FBO being set to 0. - boolean isMinimized = GLFW.glfwGetWindowAttrib(GLFW.glfwGetCurrentContext(), GLFW.GLFW_ICONIFIED) == GLFW.GLFW_TRUE; + boolean isMinimized = GLFW.glfwGetWindowAttrib(LwjglGraphics.primaryWindow, GLFW.GLFW_ICONIFIED) == GLFW.GLFW_TRUE; int i = isMinimized ? 0 : 1; propertyChangeSupport.firePropertyChange(DISPLAY_RESOLUTION_CHANGE, i, 1); } @@ -217,9 +217,8 @@ private GLFWVidMode getFullScreenDisplayMode() { } private void updateFullScreenDisplay() { - long window = GLFW.glfwGetCurrentContext(); GLFWVidMode vidMode = getFullScreenDisplayMode(); - GLFW.glfwSetWindowMonitor(window, + GLFW.glfwSetWindowMonitor(LwjglGraphics.primaryWindow, GLFW.glfwGetPrimaryMonitor(), 0, 0, diff --git a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java index a44b90d6eca..19c49998360 100644 --- a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java +++ b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java @@ -6,7 +6,6 @@ import org.lwjgl.glfw.GLFWFramebufferSizeCallback; import org.lwjgl.glfw.GLFWImage; import org.lwjgl.glfw.GLFWNativeX11; -import org.lwjgl.opengl.GL43; import org.lwjgl.system.MemoryUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,6 +30,9 @@ public class LwjglGraphics extends BaseLwjglSubsystem { private static final Logger logger = LoggerFactory.getLogger(LwjglGraphics.class); + // we don't use context so we need to + public static long primaryWindow = 0; + private Context context; private RenderingConfig config; @@ -76,9 +78,10 @@ public void postInitialise(Context rootContext) { public void postUpdate(GameState currentState, float delta) { graphics.processActions(); - boolean gameWindowIsMinimized = GLFW.glfwGetWindowAttrib(GLFW.glfwGetCurrentContext(), GLFW.GLFW_ICONIFIED) == GLFW.GLFW_TRUE; + boolean gameWindowIsMinimized = GLFW.glfwGetWindowAttrib(LwjglGraphics.primaryWindow, GLFW.GLFW_ICONIFIED) == GLFW.GLFW_TRUE; if (!gameWindowIsMinimized) { - currentState.render(); +// currentState.render(); + TeraRusty.dispatch(); } lwjglDisplay.update(); @@ -93,17 +96,17 @@ public void postUpdate(GameState currentState, float delta) { @Override public void preShutdown() { - long window = GLFW.glfwGetCurrentContext(); - if (window != MemoryUtil.NULL) { - boolean isVisible = GLFW.glfwGetWindowAttrib(window, GLFW.GLFW_VISIBLE) == GLFW.GLFW_TRUE; +// long window = GLFW.glfwGetCurrentContext(); + if (primaryWindow != MemoryUtil.NULL) { + boolean isVisible = GLFW.glfwGetWindowAttrib(primaryWindow, GLFW.GLFW_VISIBLE) == GLFW.GLFW_TRUE; boolean isFullScreen = lwjglDisplay.isFullscreen(); if (!isFullScreen && isVisible) { int[] xBuffer = new int[1]; int[] yBuffer = new int[1]; - GLFW.glfwGetWindowPos(window, xBuffer, yBuffer); + GLFW.glfwGetWindowPos(primaryWindow, xBuffer, yBuffer); int[] widthBuffer = new int[1]; int[] heightBuffer = new int[1]; - GLFW.glfwGetWindowSize(window, widthBuffer, heightBuffer); + GLFW.glfwGetWindowSize(primaryWindow, widthBuffer, heightBuffer); if (widthBuffer[0] > 0 && heightBuffer[0] > 0 && xBuffer[0] > 0 && yBuffer[0] > 0) { config.setWindowWidth(widthBuffer[0]); @@ -145,33 +148,21 @@ private void initWindow() { long window = GLFW.glfwCreateWindow( config.getWindowWidth(), config.getWindowHeight(), "Terasology Alpha", 0, 0); -// GLFWNativeX11.glfwGetX11Window(window) switch(GLFW.glfwGetPlatform()) { case GLFW.GLFW_PLATFORM_X11: TeraRusty.initializeWindowX11(GLFWNativeX11.glfwGetX11Display(), GLFWNativeX11.glfwGetX11Window(window)); break; - case GLFW.GLFW_PLATFORM_WAYLAND: - break; - case GLFW.GLFW_PLATFORM_WIN32: - break; - case GLFW.GLFW_PLATFORM_COCOA: - break; default: - break; + throw new RuntimeException("missing platform: " + GLFW.glfwGetPlatform()); } if (window == 0) { throw new RuntimeException("Failed to create window"); } + primaryWindow = window; - GLFW.glfwMakeContextCurrent(window); - - - if (!config.isVSync()) { - GLFW.glfwSwapInterval(0); - } - + TeraRusty.windowSizeChanged(lwjglDisplay.getWidth(), lwjglDisplay.getHeight()); if (OS.get() != OS.MACOSX) { try { String root = "org/terasology/engine/icons/"; @@ -200,21 +191,12 @@ private void initWindow() { } private void initOpenGL() { - logger.info("Initializing OpenGL"); - LwjglGraphicsUtil.checkOpenGL(); - GLFW.glfwSetFramebufferSizeCallback(GLFW.glfwGetCurrentContext(), new GLFWFramebufferSizeCallback() { + GLFW.glfwSetFramebufferSizeCallback(LwjglGraphics.primaryWindow, new GLFWFramebufferSizeCallback() { @Override public void invoke(long window, int width, int height) { lwjglDisplay.updateViewport(width, height); + TeraRusty.windowSizeChanged(width, height); } }); - LwjglGraphicsUtil.initOpenGLParams(); - if (config.getDebug().isEnabled()) { - try { - GL43.glDebugMessageCallback(new DebugCallback(), MemoryUtil.NULL); - } catch (IllegalStateException e) { - logger.warn("Unable to specify DebugCallback to receive debugging messages from the GL."); - } - } } } diff --git a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphicsManager.java b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphicsManager.java index b71b200f9fb..65254d625ab 100644 --- a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphicsManager.java +++ b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphicsManager.java @@ -103,7 +103,7 @@ public void registerRenderingSubsystem(Context context) { } public void processActions() { - LwjglGraphicsUtil.updateDisplayDeviceInfo(displayDeviceInfo); +// LwjglGraphicsUtil.updateDisplayDeviceInfo(displayDeviceInfo); if (!displayThreadActions.isEmpty()) { List actions = Lists.newArrayListWithExpectedSize(displayThreadActions.size()); @@ -122,68 +122,68 @@ public void asynchToDisplayThread(Runnable action) { public void createTexture3D(ByteBuffer alignedBuffer, Texture.WrapMode wrapMode, Texture.FilterMode filterMode, int size, Consumer idConsumer) { - asynchToDisplayThread(() -> { - int id = glGenTextures(); - reloadTexture3D(id, alignedBuffer, wrapMode, filterMode, size); - idConsumer.accept(id); - }); +// asynchToDisplayThread(() -> { +// int id = glGenTextures(); +// reloadTexture3D(id, alignedBuffer, wrapMode, filterMode, size); +// idConsumer.accept(id); +// }); } public void reloadTexture3D(int id, ByteBuffer alignedBuffer, Texture.WrapMode wrapMode, Texture.FilterMode filterMode, int size) { - asynchToDisplayThread(() -> { - glBindTexture(GL12.GL_TEXTURE_3D, id); - - glTexParameterf(GL12.GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, LwjglGraphicsUtil.getGLMode(wrapMode)); - glTexParameterf(GL12.GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, LwjglGraphicsUtil.getGLMode(wrapMode)); - glTexParameterf(GL12.GL_TEXTURE_3D, GL12.GL_TEXTURE_WRAP_R, LwjglGraphicsUtil.getGLMode(wrapMode)); - - GL11.glTexParameteri(GL12.GL_TEXTURE_3D, GL11.GL_TEXTURE_MIN_FILTER, - LwjglGraphicsUtil.getGlMinFilter(filterMode)); - GL11.glTexParameteri(GL12.GL_TEXTURE_3D, GL11.GL_TEXTURE_MAG_FILTER, - LwjglGraphicsUtil.getGlMagFilter(filterMode)); - - GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 4); - GL11.glTexParameteri(GL12.GL_TEXTURE_3D, GL12.GL_TEXTURE_MAX_LEVEL, 0); - - GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0, GL11.GL_RGBA, size, size, size, 0, GL11.GL_RGBA, - GL11.GL_UNSIGNED_BYTE, alignedBuffer); - }); +// asynchToDisplayThread(() -> { +// glBindTexture(GL12.GL_TEXTURE_3D, id); +// +// glTexParameterf(GL12.GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, LwjglGraphicsUtil.getGLMode(wrapMode)); +// glTexParameterf(GL12.GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, LwjglGraphicsUtil.getGLMode(wrapMode)); +// glTexParameterf(GL12.GL_TEXTURE_3D, GL12.GL_TEXTURE_WRAP_R, LwjglGraphicsUtil.getGLMode(wrapMode)); +// +// GL11.glTexParameteri(GL12.GL_TEXTURE_3D, GL11.GL_TEXTURE_MIN_FILTER, +// LwjglGraphicsUtil.getGlMinFilter(filterMode)); +// GL11.glTexParameteri(GL12.GL_TEXTURE_3D, GL11.GL_TEXTURE_MAG_FILTER, +// LwjglGraphicsUtil.getGlMagFilter(filterMode)); +// +// GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 4); +// GL11.glTexParameteri(GL12.GL_TEXTURE_3D, GL12.GL_TEXTURE_MAX_LEVEL, 0); +// +// GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0, GL11.GL_RGBA, size, size, size, 0, GL11.GL_RGBA, +// GL11.GL_UNSIGNED_BYTE, alignedBuffer); +// }); } public void createTexture2D(ByteBuffer[] buffers, Texture.WrapMode wrapMode, Texture.FilterMode filterMode, int width, int height, Consumer idConsumer) { - asynchToDisplayThread(() -> { - int id = glGenTextures(); - reloadTexture2D(id, buffers, wrapMode, filterMode, width, height); - idConsumer.accept(id); - }); +// asynchToDisplayThread(() -> { +// int id = glGenTextures(); +// reloadTexture2D(id, buffers, wrapMode, filterMode, width, height); +// idConsumer.accept(id); +// }); } public void reloadTexture2D(int id, ByteBuffer[] buffers, Texture.WrapMode wrapMode, Texture.FilterMode filterMode, int width, int height) { - asynchToDisplayThread(() -> { - glBindTexture(GL11.GL_TEXTURE_2D, id); - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, LwjglGraphicsUtil.getGLMode(wrapMode)); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, LwjglGraphicsUtil.getGLMode(wrapMode)); - GL11.glTexParameteri(GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, - LwjglGraphicsUtil.getGlMinFilter(filterMode)); - GL11.glTexParameteri(GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, - LwjglGraphicsUtil.getGlMagFilter(filterMode)); - GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 4); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, buffers.length - 1); - - if (buffers.length > 0) { - for (int i = 0; i < buffers.length; i++) { - GL11.glTexImage2D(GL11.GL_TEXTURE_2D, i, GL11.GL_RGBA, width >> i, height >> i, 0, GL11.GL_RGBA, - GL11.GL_UNSIGNED_BYTE, buffers[i]); - } - } else { - GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL11.GL_RGBA, - GL11.GL_UNSIGNED_BYTE, (ByteBuffer) null); - } - }); +// asynchToDisplayThread(() -> { +// glBindTexture(GL11.GL_TEXTURE_2D, id); +// +// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, LwjglGraphicsUtil.getGLMode(wrapMode)); +// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, LwjglGraphicsUtil.getGLMode(wrapMode)); +// GL11.glTexParameteri(GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, +// LwjglGraphicsUtil.getGlMinFilter(filterMode)); +// GL11.glTexParameteri(GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, +// LwjglGraphicsUtil.getGlMagFilter(filterMode)); +// GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 4); +// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, buffers.length - 1); +// +// if (buffers.length > 0) { +// for (int i = 0; i < buffers.length; i++) { +// GL11.glTexImage2D(GL11.GL_TEXTURE_2D, i, GL11.GL_RGBA, width >> i, height >> i, 0, GL11.GL_RGBA, +// GL11.GL_UNSIGNED_BYTE, buffers[i]); +// } +// } else { +// GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL11.GL_RGBA, +// GL11.GL_UNSIGNED_BYTE, (ByteBuffer) null); +// } +// }); } public void disposeTexture(int id) { diff --git a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphicsUtil.java b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphicsUtil.java index 29c514ffebd..025214d23f8 100644 --- a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphicsUtil.java +++ b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphicsUtil.java @@ -97,71 +97,4 @@ public static GLFWImage convertToGLFWFormat(BufferedImage image) { return result; } - public static void initOpenGLParams() { - glEnable(GL_CULL_FACE); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); - } - - public static void checkOpenGL() { - GLCapabilities capabilities = GL.createCapabilities(); - boolean[] requiredCapabilities = { - capabilities.OpenGL12, - capabilities.OpenGL14, - capabilities.OpenGL15, - capabilities.OpenGL20, - capabilities.OpenGL21, - capabilities.OpenGL30, - capabilities.OpenGL32, - capabilities.OpenGL33, - }; - - String[] capabilityNames = { - "OpenGL12", - "OpenGL14", - "OpenGL15", - "OpenGL20", - "OpenGL21", - "OpenGL30", - "OpenGL32", - "OpenGL33", - }; - - boolean canRunTheGame = true; - StringBuilder missingCapabilitiesMessage = new StringBuilder(); - - for (int index = 0; index < requiredCapabilities.length; index++) { - if (!requiredCapabilities[index]) { - missingCapabilitiesMessage.append(" - ").append(capabilityNames[index]).append("\n"); - canRunTheGame = false; - } - } - - if (!canRunTheGame) { - String completeErrorMessage = completeErrorMessage(missingCapabilitiesMessage.toString()); - throw new IllegalStateException(completeErrorMessage); - } - } - - private static String completeErrorMessage(String errorMessage) { - return "\n" + - "\nThe following OpenGL versions/extensions are required but are not supported by your GPU driver:\n" + - "\n" + - errorMessage + - "\n" + - "GPU Information:\n" + - "\n" + - " Vendor: " + GL11.glGetString(GL11.GL_VENDOR) + "\n" + - " Model: " + GL11.glGetString(GL11.GL_RENDERER) + "\n" + - " Driver: " + GL11.glGetString(GL11.GL_VERSION) + "\n" + - "\n" + - "Try updating the driver to the latest version available.\n" + - "If that fails you might need to use a different GPU (graphics card). Sorry!\n"; - } - - public static void updateDisplayDeviceInfo(DisplayDeviceInfo deviceInfo) { - deviceInfo.setOpenGlVendor(GL11.glGetString(GL11.GL_VENDOR)); - deviceInfo.setOpenGlVersion(GL11.glGetString(GL11.GL_VERSION)); - deviceInfo.setOpenGlRenderer(GL11.glGetString(GL11.GL_RENDERER)); - } } diff --git a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglInput.java b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglInput.java index 77245b4db04..bdb576dbc51 100644 --- a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglInput.java +++ b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglInput.java @@ -51,9 +51,9 @@ private void initControls() { LwjglControllerDevice controllerDevice = new LwjglControllerDevice(controllerConfig); inputSystem.setControllerDevice(controllerDevice); - long window = GLFW.glfwGetCurrentContext(); - ((LwjglKeyboardDevice) inputSystem.getKeyboard()).registerToLwjglWindow(window); - ((LwjglMouseDevice) inputSystem.getMouseDevice()).registerToLwjglWindow(window); +// long window = GLFW.glfwGetCurrentContext(); + ((LwjglKeyboardDevice) inputSystem.getKeyboard()).registerToLwjglWindow(LwjglGraphics.primaryWindow); + ((LwjglMouseDevice) inputSystem.getMouseDevice()).registerToLwjglWindow(LwjglGraphics.primaryWindow); } private void updateInputConfig() { diff --git a/engine/src/main/java/org/terasology/engine/input/lwjgl/LwjglMouseDevice.java b/engine/src/main/java/org/terasology/engine/input/lwjgl/LwjglMouseDevice.java index 104baa6b228..03fdf21cef9 100644 --- a/engine/src/main/java/org/terasology/engine/input/lwjgl/LwjglMouseDevice.java +++ b/engine/src/main/java/org/terasology/engine/input/lwjgl/LwjglMouseDevice.java @@ -11,6 +11,7 @@ import org.lwjgl.BufferUtils; import org.lwjgl.glfw.GLFW; import org.terasology.engine.config.RenderingConfig; +import org.terasology.engine.core.subsystem.lwjgl.LwjglGraphics; import org.terasology.input.ButtonState; import org.terasology.input.InputType; import org.terasology.input.MouseInput; @@ -55,11 +56,11 @@ public void registerToLwjglWindow(long window) { @Override public void update() { - long window = GLFW.glfwGetCurrentContext(); +// long window = GLFW.glfwGetCurrentContext(); DoubleBuffer mouseX = BufferUtils.createDoubleBuffer(1); DoubleBuffer mouseY = BufferUtils.createDoubleBuffer(1); - GLFW.glfwGetCursorPos(window, mouseX, mouseY); + GLFW.glfwGetCursorPos(LwjglGraphics.primaryWindow, mouseX, mouseY); double x = mouseX.get(0); double y = mouseY.get(0); @@ -95,7 +96,7 @@ public boolean isVisible() { public void setGrabbed(boolean newGrabbed) { if (newGrabbed != mouseGrabbed) { mouseGrabbed = newGrabbed; - GLFW.glfwSetInputMode(GLFW.glfwGetCurrentContext(), GLFW.GLFW_CURSOR, + GLFW.glfwSetInputMode(LwjglGraphics.primaryWindow, GLFW.GLFW_CURSOR, newGrabbed ? GLFW.GLFW_CURSOR_DISABLED : GLFW.GLFW_CURSOR_NORMAL); } } diff --git a/engine/src/main/java/org/terasology/engine/rendering/opengl/GLSLMaterial.java b/engine/src/main/java/org/terasology/engine/rendering/opengl/GLSLMaterial.java index 3a65a2d0bc3..f42cdddc9c3 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/opengl/GLSLMaterial.java +++ b/engine/src/main/java/org/terasology/engine/rendering/opengl/GLSLMaterial.java @@ -252,25 +252,25 @@ public boolean supportsFeature(ShaderProgramFeature feature) { @Override public void setFloat(String desc, float f, boolean currentOnly) { - if (isDisposed()) { - return; - } - if (currentOnly) { - enable(); - int id = getUniformLocation(getActiveShaderProgramId(), desc); - GL20.glUniform1f(id, f); - } else { - TIntIntIterator it = disposalAction.shaderPrograms.iterator(); - while (it.hasNext()) { - it.advance(); - - GL20.glUseProgram(it.value()); - int id = getUniformLocation(it.value(), desc); - GL20.glUniform1f(id, f); - } - - restoreStateAfterUniformsSet(); - } +// if (isDisposed()) { +// return; +// } +// if (currentOnly) { +// enable(); +// int id = getUniformLocation(getActiveShaderProgramId(), desc); +// GL20.glUniform1f(id, f); +// } else { +// TIntIntIterator it = disposalAction.shaderPrograms.iterator(); +// while (it.hasNext()) { +// it.advance(); +// +// GL20.glUseProgram(it.value()); +// int id = getUniformLocation(it.value(), desc); +// GL20.glUniform1f(id, f); +// } +// +// restoreStateAfterUniformsSet(); +// } } @Override @@ -298,282 +298,283 @@ public void setFloat1(String desc, FloatBuffer buffer, boolean currentOnly) { @Override public void setFloat2(String desc, float f1, float f2, boolean currentOnly) { - if (isDisposed()) { - return; - } - if (currentOnly) { - enable(); - int id = getUniformLocation(getActiveShaderProgramId(), desc); - GL20.glUniform2f(id, f1, f2); - } else { - TIntIntIterator it = disposalAction.shaderPrograms.iterator(); - while (it.hasNext()) { - it.advance(); - - GL20.glUseProgram(it.value()); - int id = getUniformLocation(it.value(), desc); - GL20.glUniform2f(id, f1, f2); - } - - restoreStateAfterUniformsSet(); - } +// return; +// if (isDisposed()) { +// return; +// } +// if (currentOnly) { +// enable(); +// int id = getUniformLocation(getActiveShaderProgramId(), desc); +// GL20.glUniform2f(id, f1, f2); +// } else { +// TIntIntIterator it = disposalAction.shaderPrograms.iterator(); +// while (it.hasNext()) { +// it.advance(); +// +// GL20.glUseProgram(it.value()); +// int id = getUniformLocation(it.value(), desc); +// GL20.glUniform2f(id, f1, f2); +// } +// +// restoreStateAfterUniformsSet(); +// } } @Override public void setFloat2(String desc, FloatBuffer buffer, boolean currentOnly) { - if (isDisposed()) { - return; - } - if (currentOnly) { - enable(); - int id = getUniformLocation(getActiveShaderProgramId(), desc); - GL20.glUniform2fv(id, buffer); - } else { - TIntIntIterator it = disposalAction.shaderPrograms.iterator(); - while (it.hasNext()) { - it.advance(); - - GL20.glUseProgram(it.value()); - int id = getUniformLocation(it.value(), desc); - GL20.glUniform2fv(id, buffer); - } - - restoreStateAfterUniformsSet(); - } +// if (isDisposed()) { +// return; +// } +// if (currentOnly) { +// enable(); +// int id = getUniformLocation(getActiveShaderProgramId(), desc); +// GL20.glUniform2fv(id, buffer); +// } else { +// TIntIntIterator it = disposalAction.shaderPrograms.iterator(); +// while (it.hasNext()) { +// it.advance(); +// +// GL20.glUseProgram(it.value()); +// int id = getUniformLocation(it.value(), desc); +// GL20.glUniform2fv(id, buffer); +// } +// +// restoreStateAfterUniformsSet(); +// } } @Override public void setFloat3(String desc, float f1, float f2, float f3, boolean currentOnly) { - if (isDisposed()) { - return; - } - if (currentOnly) { - enable(); - int id = getUniformLocation(getActiveShaderProgramId(), desc); - GL20.glUniform3f(id, f1, f2, f3); - } else { - TIntIntIterator it = disposalAction.shaderPrograms.iterator(); - while (it.hasNext()) { - it.advance(); - - GL20.glUseProgram(it.value()); - int id = getUniformLocation(it.value(), desc); - GL20.glUniform3f(id, f1, f2, f3); - } - - restoreStateAfterUniformsSet(); - } +// if (isDisposed()) { +// return; +// } +// if (currentOnly) { +// enable(); +// int id = getUniformLocation(getActiveShaderProgramId(), desc); +// GL20.glUniform3f(id, f1, f2, f3); +// } else { +// TIntIntIterator it = disposalAction.shaderPrograms.iterator(); +// while (it.hasNext()) { +// it.advance(); +// +// GL20.glUseProgram(it.value()); +// int id = getUniformLocation(it.value(), desc); +// GL20.glUniform3f(id, f1, f2, f3); +// } +// +// restoreStateAfterUniformsSet(); +// } } @Override public void setFloat3(String desc, FloatBuffer buffer, boolean currentOnly) { - if (isDisposed()) { - return; - } - if (currentOnly) { - enable(); - int id = getUniformLocation(getActiveShaderProgramId(), desc); - GL20.glUniform3fv(id, buffer); - } else { - TIntIntIterator it = disposalAction.shaderPrograms.iterator(); - while (it.hasNext()) { - it.advance(); - - GL20.glUseProgram(it.value()); - int id = getUniformLocation(it.value(), desc); - GL20.glUniform3fv(id, buffer); - } - - restoreStateAfterUniformsSet(); - } +// if (isDisposed()) { +// return; +// } +// if (currentOnly) { +// enable(); +// int id = getUniformLocation(getActiveShaderProgramId(), desc); +// GL20.glUniform3fv(id, buffer); +// } else { +// TIntIntIterator it = disposalAction.shaderPrograms.iterator(); +// while (it.hasNext()) { +// it.advance(); +// +// GL20.glUseProgram(it.value()); +// int id = getUniformLocation(it.value(), desc); +// GL20.glUniform3fv(id, buffer); +// } +// +// restoreStateAfterUniformsSet(); +// } } @Override public void setFloat4(String desc, float f1, float f2, float f3, float f4, boolean currentOnly) { - if (isDisposed()) { - return; - } - if (currentOnly) { - enable(); - int id = getUniformLocation(getActiveShaderProgramId(), desc); - GL20.glUniform4f(id, f1, f2, f3, f4); - } else { - TIntIntIterator it = disposalAction.shaderPrograms.iterator(); - while (it.hasNext()) { - it.advance(); - - GL20.glUseProgram(it.value()); - int id = getUniformLocation(it.value(), desc); - GL20.glUniform4f(id, f1, f2, f3, f4); - } - - restoreStateAfterUniformsSet(); - } +// if (isDisposed()) { +// return; +// } +// if (currentOnly) { +// enable(); +// int id = getUniformLocation(getActiveShaderProgramId(), desc); +// GL20.glUniform4f(id, f1, f2, f3, f4); +// } else { +// TIntIntIterator it = disposalAction.shaderPrograms.iterator(); +// while (it.hasNext()) { +// it.advance(); +// +// GL20.glUseProgram(it.value()); +// int id = getUniformLocation(it.value(), desc); +// GL20.glUniform4f(id, f1, f2, f3, f4); +// } +// +// restoreStateAfterUniformsSet(); +// } } @Override public void setFloat4(String desc, FloatBuffer buffer, boolean currentOnly) { - if (isDisposed()) { - return; - } - if (currentOnly) { - enable(); - int id = getUniformLocation(getActiveShaderProgramId(), desc); - GL20.glUniform4fv(id, buffer); - } else { - TIntIntIterator it = disposalAction.shaderPrograms.iterator(); - while (it.hasNext()) { - it.advance(); - - GL20.glUseProgram(it.value()); - int id = getUniformLocation(it.value(), desc); - GL20.glUniform4fv(id, buffer); - } - - restoreStateAfterUniformsSet(); - } +// if (isDisposed()) { +// return; +// } +// if (currentOnly) { +// enable(); +// int id = getUniformLocation(getActiveShaderProgramId(), desc); +// GL20.glUniform4fv(id, buffer); +// } else { +// TIntIntIterator it = disposalAction.shaderPrograms.iterator(); +// while (it.hasNext()) { +// it.advance(); +// +// GL20.glUseProgram(it.value()); +// int id = getUniformLocation(it.value(), desc); +// GL20.glUniform4fv(id, buffer); +// } +// +// restoreStateAfterUniformsSet(); +// } } @Override public void setInt(String desc, int i, boolean currentOnly) { - if (isDisposed()) { - return; - } - if (currentOnly) { - enable(); - int id = getUniformLocation(getActiveShaderProgramId(), desc); - GL20.glUniform1i(id, i); - } else { - TIntIntIterator it = disposalAction.shaderPrograms.iterator(); - while (it.hasNext()) { - it.advance(); - - GL20.glUseProgram(it.value()); - int id = getUniformLocation(it.value(), desc); - GL20.glUniform1i(id, i); - } - - restoreStateAfterUniformsSet(); - } +// if (isDisposed()) { +// return; +// } +// if (currentOnly) { +// enable(); +// int id = getUniformLocation(getActiveShaderProgramId(), desc); +// GL20.glUniform1i(id, i); +// } else { +// TIntIntIterator it = disposalAction.shaderPrograms.iterator(); +// while (it.hasNext()) { +// it.advance(); +// +// GL20.glUseProgram(it.value()); +// int id = getUniformLocation(it.value(), desc); +// GL20.glUniform1i(id, i); +// } +// +// restoreStateAfterUniformsSet(); +// } } @Override public void setBoolean(String desc, boolean value, boolean currentOnly) { - if (isDisposed()) { - return; - } - if (currentOnly) { - enable(); - int id = getUniformLocation(getActiveShaderProgramId(), desc); - GL20.glUniform1i(id, value ? 1 : 0); - } else { - TIntIntIterator it = disposalAction.shaderPrograms.iterator(); - while (it.hasNext()) { - it.advance(); - - GL20.glUseProgram(it.value()); - int id = getUniformLocation(it.value(), desc); - GL20.glUniform1i(id, value ? 1 : 0); - } - - restoreStateAfterUniformsSet(); - } +// if (isDisposed()) { +// return; +// } +// if (currentOnly) { +// enable(); +// int id = getUniformLocation(getActiveShaderProgramId(), desc); +// GL20.glUniform1i(id, value ? 1 : 0); +// } else { +// TIntIntIterator it = disposalAction.shaderPrograms.iterator(); +// while (it.hasNext()) { +// it.advance(); +// +// GL20.glUseProgram(it.value()); +// int id = getUniformLocation(it.value(), desc); +// GL20.glUniform1i(id, value ? 1 : 0); +// } +// +// restoreStateAfterUniformsSet(); +// } } @Override public void setMatrix3(String desc, Matrix3fc value, boolean currentOnly) { - if (isDisposed()) { - return; - } - matrixBuffer.rewind(); - value.get(matrixBuffer); - if (currentOnly) { - enable(); - int id = getUniformLocation(getActiveShaderProgramId(), desc); - GL20.glUniformMatrix3fv(id, false, matrixBuffer); - } else { - TIntIntIterator it = disposalAction.shaderPrograms.iterator(); - while (it.hasNext()) { - it.advance(); - - GL20.glUseProgram(it.value()); - int id = getUniformLocation(it.value(), desc); - GL20.glUniformMatrix3fv(id, false, matrixBuffer); - } - - restoreStateAfterUniformsSet(); - } +// if (isDisposed()) { +// return; +// } +// matrixBuffer.rewind(); +// value.get(matrixBuffer); +// if (currentOnly) { +// enable(); +// int id = getUniformLocation(getActiveShaderProgramId(), desc); +// GL20.glUniformMatrix3fv(id, false, matrixBuffer); +// } else { +// TIntIntIterator it = disposalAction.shaderPrograms.iterator(); +// while (it.hasNext()) { +// it.advance(); +// +// GL20.glUseProgram(it.value()); +// int id = getUniformLocation(it.value(), desc); +// GL20.glUniformMatrix3fv(id, false, matrixBuffer); +// } +// +// restoreStateAfterUniformsSet(); +// } } @Override public void setMatrix3(String desc, FloatBuffer value, boolean currentOnly) { - if (isDisposed()) { - return; - } - if (currentOnly) { - enable(); - int id = getUniformLocation(getActiveShaderProgramId(), desc); - GL20.glUniformMatrix3fv(id, false, value); - } else { - TIntIntIterator it = disposalAction.shaderPrograms.iterator(); - while (it.hasNext()) { - it.advance(); - - GL20.glUseProgram(it.value()); - int id = getUniformLocation(it.value(), desc); - GL20.glUniformMatrix3fv(id, false, value); - } - - restoreStateAfterUniformsSet(); - } +// if (isDisposed()) { +// return; +// } +// if (currentOnly) { +// enable(); +// int id = getUniformLocation(getActiveShaderProgramId(), desc); +// GL20.glUniformMatrix3fv(id, false, value); +// } else { +// TIntIntIterator it = disposalAction.shaderPrograms.iterator(); +// while (it.hasNext()) { +// it.advance(); +// +// GL20.glUseProgram(it.value()); +// int id = getUniformLocation(it.value(), desc); +// GL20.glUniformMatrix3fv(id, false, value); +// } +// +// restoreStateAfterUniformsSet(); +// } } @Override public void setMatrix4(String desc, Matrix4fc value, boolean currentOnly) { - if (isDisposed()) { - return; - } - matrixBuffer.rewind(); - value.get(matrixBuffer); - if (currentOnly) { - enable(); - int id = getUniformLocation(getActiveShaderProgramId(), desc); - GL20.glUniformMatrix4fv(id, false, matrixBuffer); - } else { - TIntIntIterator it = disposalAction.shaderPrograms.iterator(); - while (it.hasNext()) { - it.advance(); - - GL20.glUseProgram(it.value()); - int id = getUniformLocation(it.value(), desc); - GL20.glUniformMatrix4fv(id, false, matrixBuffer); - } - - restoreStateAfterUniformsSet(); - } +// if (isDisposed()) { +// return; +// } +// matrixBuffer.rewind(); +// value.get(matrixBuffer); +// if (currentOnly) { +// enable(); +// int id = getUniformLocation(getActiveShaderProgramId(), desc); +// GL20.glUniformMatrix4fv(id, false, matrixBuffer); +// } else { +// TIntIntIterator it = disposalAction.shaderPrograms.iterator(); +// while (it.hasNext()) { +// it.advance(); +// +// GL20.glUseProgram(it.value()); +// int id = getUniformLocation(it.value(), desc); +// GL20.glUniformMatrix4fv(id, false, matrixBuffer); +// } +// +// restoreStateAfterUniformsSet(); +// } } @Override public void setMatrix4(String desc, FloatBuffer value, boolean currentOnly) { - if (isDisposed()) { - return; - } - if (currentOnly) { - enable(); - int id = getUniformLocation(getActiveShaderProgramId(), desc); - GL20.glUniformMatrix4fv(id, false, value); - } else { - TIntIntIterator it = disposalAction.shaderPrograms.iterator(); - while (it.hasNext()) { - it.advance(); - - GL20.glUseProgram(it.value()); - int id = getUniformLocation(it.value(), desc); - GL20.glUniformMatrix4fv(id, false, value); - } - - restoreStateAfterUniformsSet(); - } +// if (isDisposed()) { +// return; +// } +// if (currentOnly) { +// enable(); +// int id = getUniformLocation(getActiveShaderProgramId(), desc); +// GL20.glUniformMatrix4fv(id, false, value); +// } else { +// TIntIntIterator it = disposalAction.shaderPrograms.iterator(); +// while (it.hasNext()) { +// it.advance(); +// +// GL20.glUseProgram(it.value()); +// int id = getUniformLocation(it.value(), desc); +// GL20.glUniformMatrix4fv(id, false, value); +// } +// +// restoreStateAfterUniformsSet(); +// } } private int getActiveShaderProgramId() { diff --git a/engine/src/main/java/org/terasology/engine/rendering/opengl/GLSLShader.java b/engine/src/main/java/org/terasology/engine/rendering/opengl/GLSLShader.java index c29a538c519..37b5c19ab9e 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/opengl/GLSLShader.java +++ b/engine/src/main/java/org/terasology/engine/rendering/opengl/GLSLShader.java @@ -118,22 +118,22 @@ Set getAvailableFeatures() { // made package-private after CheckStyle suggestion int linkShaderProgram(int featureHash) { - int shaderProgram = GL20.glCreateProgram(); - - GL20.glAttachShader(shaderProgram, disposalAction.fragmentPrograms.get(featureHash)); - GL20.glAttachShader(shaderProgram, disposalAction.vertexPrograms.get(featureHash)); - if (shaderProgramBase.getGeometryProgram() != null) { - GL20.glAttachShader(shaderProgram, disposalAction.geometryPrograms.get(featureHash)); - } - GL20.glLinkProgram(shaderProgram); - GL20.glValidateProgram(shaderProgram); - return shaderProgram; +// int shaderProgram = GL20.glCreateProgram(); +// +// GL20.glAttachShader(shaderProgram, disposalAction.fragmentPrograms.get(featureHash)); +// GL20.glAttachShader(shaderProgram, disposalAction.vertexPrograms.get(featureHash)); +// if (shaderProgramBase.getGeometryProgram() != null) { +// GL20.glAttachShader(shaderProgram, disposalAction.geometryPrograms.get(featureHash)); +// } +// GL20.glLinkProgram(shaderProgram); +// GL20.glValidateProgram(shaderProgram); + return 0; } @Override public void recompile() { graphicsProcessing.asynchToDisplayThread(() -> { - registerAllShaderPermutations(); +// registerAllShaderPermutations(); }); } @@ -257,29 +257,6 @@ private void updateAvailableFeatures() { } } - /** - * Compiles all combination of available features and stores them in two maps for - * lookup based on a unique hash of features. - */ - private void registerAllShaderPermutations() { - Set> allPermutations = Sets.powerSet(availableFeatures); - - for (Set permutation : allPermutations) { - int featureHash = ShaderProgramFeature.getBitset(permutation); - - int fragShaderId = compileShader(GL20.GL_FRAGMENT_SHADER, permutation); - int vertShaderId = compileShader(GL20.GL_VERTEX_SHADER, permutation); - if (shaderProgramBase.getGeometryProgram() != null) { - int geomShaderId = compileShader(GL32.GL_GEOMETRY_SHADER, permutation); - disposalAction.geometryPrograms.put(featureHash, geomShaderId); - } - - disposalAction.fragmentPrograms.put(featureHash, fragShaderId); - disposalAction.vertexPrograms.put(featureHash, vertShaderId); - } - - logger.debug("Compiled {} permutations for {}.", allPermutations.size(), getUrn()); - } private String assembleShader(int type, Set features) { StringBuilder shader = createShaderBuilder(); @@ -365,19 +342,20 @@ protected void doReload(ShaderData data) { try { GameThread.synch(() -> { logger.debug("Recompiling shader {}.", getUrn()); - - disposalAction.disposeData(); - shaderProgramBase = data; - parameters.clear(); - for (ShaderParameterMetadata metadata : shaderProgramBase.getParameterMetadata()) { - parameters.put(metadata.getName(), metadata); - } - updateAvailableFeatures(); - try { - registerAllShaderPermutations(); - } catch (RuntimeException e) { - logger.warn(e.getMessage()); - } + //TODO implement shader +// +// disposalAction.disposeData(); +// shaderProgramBase = data; +// parameters.clear(); +// for (ShaderParameterMetadata metadata : shaderProgramBase.getParameterMetadata()) { +// parameters.put(metadata.getName(), metadata); +// } +// updateAvailableFeatures(); +// try { +// registerAllShaderPermutations(); +// } catch (RuntimeException e) { +// logger.warn(e.getMessage()); +// } }); } catch (InterruptedException e) { logger.error("Failed to reload {}", getUrn(), e); diff --git a/engine/src/main/java/org/terasology/engine/rendering/opengl/OpenGLMesh.java b/engine/src/main/java/org/terasology/engine/rendering/opengl/OpenGLMesh.java index 0a52d1f7e67..e023d58b494 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/opengl/OpenGLMesh.java +++ b/engine/src/main/java/org/terasology/engine/rendering/opengl/OpenGLMesh.java @@ -92,26 +92,26 @@ public void render() { private void buildMesh(MeshData newData) { - if (this.disposalAction.vao == 0) { - this.disposalAction.vao = GL30.glGenVertexArrays(); - this.disposalAction.vbo = GL30.glGenBuffers(); - this.disposalAction.ebo = GL30.glGenBuffers(); - } - - allocationType = newData.allocationType(); - drawMode = newData.getMode(); - - GL30.glBindVertexArray(this.disposalAction.vao); - positions = newData.positions(); - this.state = buildVBO(this.disposalAction.vbo, allocationType, newData.vertexResources()); - - IndexResource indexResource = newData.indexResource(); - this.indexCount = indexResource.indices(); - GL30.glBindBuffer(GL30.GL_ELEMENT_ARRAY_BUFFER, this.disposalAction.ebo); - indexResource.writeBuffer((buffer) -> GL30.glBufferData(GL30.GL_ELEMENT_ARRAY_BUFFER, buffer, GL30.GL_STATIC_DRAW)); - - GL30.glBindVertexArray(0); - getBound(aabb); +// if (this.disposalAction.vao == 0) { +// this.disposalAction.vao = GL30.glGenVertexArrays(); +// this.disposalAction.vbo = GL30.glGenBuffers(); +// this.disposalAction.ebo = GL30.glGenBuffers(); +// } +// +// allocationType = newData.allocationType(); +// drawMode = newData.getMode(); +// +// GL30.glBindVertexArray(this.disposalAction.vao); +// positions = newData.positions(); +// this.state = buildVBO(this.disposalAction.vbo, allocationType, newData.vertexResources()); +// +// IndexResource indexResource = newData.indexResource(); +// this.indexCount = indexResource.indices(); +// GL30.glBindBuffer(GL30.GL_ELEMENT_ARRAY_BUFFER, this.disposalAction.ebo); +// indexResource.writeBuffer((buffer) -> GL30.glBufferData(GL30.GL_ELEMENT_ARRAY_BUFFER, buffer, GL30.GL_STATIC_DRAW)); +// +// GL30.glBindVertexArray(0); +// getBound(aabb); } private static class DisposalAction implements DisposableResource { @@ -127,18 +127,18 @@ private static class DisposalAction implements DisposableResource { } public void dispose() { - if (vao != 0) { - GL30.glDeleteVertexArrays(vao); - } - if (vbo != 0) { - GL30.glDeleteBuffers(vbo); - } - if (ebo != 0) { - GL30.glDeleteBuffers(ebo); - } - vao = 0; - vbo = 0; - ebo = 0; +// if (vao != 0) { +// GL30.glDeleteVertexArrays(vao); +// } +// if (vbo != 0) { +// GL30.glDeleteBuffers(vbo); +// } +// if (ebo != 0) { +// GL30.glDeleteBuffers(ebo); +// } +// vao = 0; +// vbo = 0; +// ebo = 0; } @Override diff --git a/engine/src/main/java/org/terasology/engine/rendering/opengl/OpenGLTexture.java b/engine/src/main/java/org/terasology/engine/rendering/opengl/OpenGLTexture.java index 13a89423715..f807287bda5 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/opengl/OpenGLTexture.java +++ b/engine/src/main/java/org/terasology/engine/rendering/opengl/OpenGLTexture.java @@ -41,78 +41,78 @@ public void setId(int id) { @Override protected void doReload(TextureData data) { - switch (data.getType()) { - // TODO: reconsider how 3D textures handled (probably separate asset implementation with common interface? - case TEXTURE3D: - if (data.getWidth() % data.getHeight() != 0 || data.getWidth() / data.getHeight() != data.getHeight()) { - throw new RuntimeException("3D texture must be cubic (height^3) - width must thus be a multiple of height"); - } - int size = data.getHeight(); - - final int byteLength = 4 * 16 * 16 * 16; - final int strideX = 16 * 4; - final int strideY = 16 * 16 * 4; - final int strideZ = 4; - - ByteBuffer alignedBuffer = ByteBuffer.allocateDirect(byteLength); - for (int x = 0; x < size; x++) { - for (int y = 0; y < size; y++) { - for (int z = 0; z < size; z++) { - final int index = x * strideX + z * strideZ + strideY * y; - - alignedBuffer.put(data.getBuffers()[0].get(index)); - alignedBuffer.put(data.getBuffers()[0].get(index + 1)); - alignedBuffer.put(data.getBuffers()[0].get(index + 2)); - alignedBuffer.put(data.getBuffers()[0].get(index + 3)); - } - } - } - alignedBuffer.flip(); - - resources.loadedTextureInfo = new LoadedTextureInfo(size, size, size, data); - - if (resources.id == 0) { - resources.graphicsManager.createTexture3D(alignedBuffer, getWrapMode(), getFilterMode(), - size, (newId) -> { - synchronized (this) { - if (resources.id != 0) { - resources.graphicsManager.disposeTexture(resources.id); - } - if (isDisposed()) { - resources.graphicsManager.disposeTexture(newId); - } else { - resources.id = newId; - logger.debug("Bound texture '{}' - {}", getUrn(), resources.id); - } - } - }); - } else { - resources.graphicsManager.reloadTexture3D(resources.id, alignedBuffer, getWrapMode(), getFilterMode(), size); - } - break; - default: - int width = data.getWidth(); - int height = data.getHeight(); - resources.loadedTextureInfo = new LoadedTextureInfo(width, height, 1, data); - if (resources.id == 0) { - resources.graphicsManager.createTexture2D(data.getBuffers(), getWrapMode(), getFilterMode(), width, height, (newId) -> { - synchronized (this) { - if (resources.id != 0) { - resources.graphicsManager.disposeTexture(resources.id); - } - if (isDisposed()) { - resources.graphicsManager.disposeTexture(newId); - } else { - resources.id = newId; - logger.debug("Bound texture '{}' - {}", getUrn(), resources.id); - } - } - }); - } else { - resources.graphicsManager.reloadTexture2D(resources.id, data.getBuffers(), getWrapMode(), getFilterMode(), width, height); - } - break; - } +// switch (data.getType()) { +// // TODO: reconsider how 3D textures handled (probably separate asset implementation with common interface? +// case TEXTURE3D: +// if (data.getWidth() % data.getHeight() != 0 || data.getWidth() / data.getHeight() != data.getHeight()) { +// throw new RuntimeException("3D texture must be cubic (height^3) - width must thus be a multiple of height"); +// } +// int size = data.getHeight(); +// +// final int byteLength = 4 * 16 * 16 * 16; +// final int strideX = 16 * 4; +// final int strideY = 16 * 16 * 4; +// final int strideZ = 4; +// +// ByteBuffer alignedBuffer = ByteBuffer.allocateDirect(byteLength); +// for (int x = 0; x < size; x++) { +// for (int y = 0; y < size; y++) { +// for (int z = 0; z < size; z++) { +// final int index = x * strideX + z * strideZ + strideY * y; +// +// alignedBuffer.put(data.getBuffers()[0].get(index)); +// alignedBuffer.put(data.getBuffers()[0].get(index + 1)); +// alignedBuffer.put(data.getBuffers()[0].get(index + 2)); +// alignedBuffer.put(data.getBuffers()[0].get(index + 3)); +// } +// } +// } +// alignedBuffer.flip(); +// +// resources.loadedTextureInfo = new LoadedTextureInfo(size, size, size, data); +// +// if (resources.id == 0) { +// resources.graphicsManager.createTexture3D(alignedBuffer, getWrapMode(), getFilterMode(), +// size, (newId) -> { +// synchronized (this) { +// if (resources.id != 0) { +// resources.graphicsManager.disposeTexture(resources.id); +// } +// if (isDisposed()) { +// resources.graphicsManager.disposeTexture(newId); +// } else { +// resources.id = newId; +// logger.debug("Bound texture '{}' - {}", getUrn(), resources.id); +// } +// } +// }); +// } else { +// resources.graphicsManager.reloadTexture3D(resources.id, alignedBuffer, getWrapMode(), getFilterMode(), size); +// } +// break; +// default: +// int width = data.getWidth(); +// int height = data.getHeight(); +// resources.loadedTextureInfo = new LoadedTextureInfo(width, height, 1, data); +// if (resources.id == 0) { +// resources.graphicsManager.createTexture2D(data.getBuffers(), getWrapMode(), getFilterMode(), width, height, (newId) -> { +// synchronized (this) { +// if (resources.id != 0) { +// resources.graphicsManager.disposeTexture(resources.id); +// } +// if (isDisposed()) { +// resources.graphicsManager.disposeTexture(newId); +// } else { +// resources.id = newId; +// logger.debug("Bound texture '{}' - {}", getUrn(), resources.id); +// } +// } +// }); +// } else { +// resources.graphicsManager.reloadTexture2D(resources.id, data.getBuffers(), getWrapMode(), getFilterMode(), width, height); +// } +// break; +// } } @Override diff --git a/engine/src/main/java/org/terasology/engine/rendering/world/WorldRendererImpl.java b/engine/src/main/java/org/terasology/engine/rendering/world/WorldRendererImpl.java index 9c31f081178..f2462052736 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/world/WorldRendererImpl.java +++ b/engine/src/main/java/org/terasology/engine/rendering/world/WorldRendererImpl.java @@ -337,7 +337,7 @@ public void render(RenderingStage renderingStage) { renderPipelineTaskList.forEach(RenderPipelineTask::process); // this line re-establish Terasology defaults, so that the rest of the application can rely on them. - LwjglGraphicsUtil.initOpenGLParams(); +// LwjglGraphicsUtil.initOpenGLParams(); playerCamera.updatePrevViewProjectionMatrix(); } From 72c785b3e6a136a66ea3ea66a1d0817397ef2cde Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Mon, 10 Jul 2023 21:51:40 -0700 Subject: [PATCH 03/13] rework rendering logic Signed-off-by: Michael Pollind --- .../engine/core/TerasologyEngine.java | 7 + .../core/subsystem/lwjgl/LwjglGraphics.java | 135 +++++++++--------- .../org/terasology/engine/Terasology.java | 14 +- 3 files changed, 78 insertions(+), 78 deletions(-) diff --git a/engine/src/main/java/org/terasology/engine/core/TerasologyEngine.java b/engine/src/main/java/org/terasology/engine/core/TerasologyEngine.java index 7e989e34910..dec334b0aa7 100644 --- a/engine/src/main/java/org/terasology/engine/core/TerasologyEngine.java +++ b/engine/src/main/java/org/terasology/engine/core/TerasologyEngine.java @@ -43,6 +43,7 @@ import org.terasology.engine.recording.RecordAndReplayUtils; import org.terasology.engine.registry.CoreRegistry; import org.terasology.engine.rendering.gltf.ByteBufferAsset; +import org.terasology.engine.rust.EngineKernel; import org.terasology.engine.version.TerasologyVersion; import org.terasology.engine.world.block.loader.BlockFamilyDefinition; import org.terasology.engine.world.block.loader.BlockFamilyDefinitionData; @@ -121,6 +122,7 @@ public class TerasologyEngine implements GameEngine { private Set stateChangeSubscribers = Sets.newLinkedHashSet(); private EngineStatus status = StandardGameStatus.UNSTARTED; + private EngineKernel kernel; private final List statusSubscriberList = new CopyOnWriteArrayList<>(); private volatile boolean shutdownRequested; @@ -161,6 +163,9 @@ public TerasologyEngine(TimeSubsystem timeSubsystem, Collection rootContext.put(CharacterStateEventPositionMap.class, characterStateEventPositionMap); DirectionAndOriginPosRecorderList directionAndOriginPosRecorderList = new DirectionAndOriginPosRecorderList(); rootContext.put(DirectionAndOriginPosRecorderList.class, directionAndOriginPosRecorderList); + + kernel = new EngineKernel(); + rootContext.put(EngineKernel.class, kernel); /* * We can't load the engine without core registry yet. * e.g. the statically created MaterialLoader needs the CoreRegistry to get the AssetManager. @@ -556,6 +561,7 @@ public void cleanup() { logger.error("Error shutting down {} subsystem", subsystem.getName(), e); } } + kernel.dispose(); } /** @@ -564,6 +570,7 @@ public void cleanup() { */ @Override public void shutdown() { + shutdownRequested = true; } diff --git a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java index 19c49998360..1d7b3a1cc3e 100644 --- a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java +++ b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java @@ -18,7 +18,7 @@ import org.terasology.engine.rendering.ShaderManager; import org.terasology.engine.rendering.ShaderManagerLwjgl; import org.terasology.engine.rendering.nui.internal.LwjglCanvasRenderer; -import org.terasology.engine.rust.TeraRusty; +import org.terasology.engine.rust.EngineKernel; import org.terasology.engine.utilities.OS; import org.terasology.gestalt.assets.module.ModuleAwareAssetTypeManager; import org.terasology.nui.canvas.CanvasRenderer; @@ -38,6 +38,7 @@ public class LwjglGraphics extends BaseLwjglSubsystem { private GameEngine engine; private LwjglDisplayDevice lwjglDisplay; + private EngineKernel kernel; private LwjglGraphicsManager graphics = new LwjglGraphicsManager(); @@ -65,65 +66,8 @@ public void registerCoreAssetTypes(ModuleAwareAssetTypeManager assetTypeManager) @Override public void postInitialise(Context rootContext) { graphics.registerRenderingSubsystem(context); + this.kernel = context.get(EngineKernel.class); - initGLFW(); - initWindow(); - initOpenGL(); - - context.put(ShaderManager.class, new ShaderManagerLwjgl()); - context.put(CanvasRenderer.class, new LwjglCanvasRenderer(context)); - } - - @Override - public void postUpdate(GameState currentState, float delta) { - graphics.processActions(); - - boolean gameWindowIsMinimized = GLFW.glfwGetWindowAttrib(LwjglGraphics.primaryWindow, GLFW.GLFW_ICONIFIED) == GLFW.GLFW_TRUE; - if (!gameWindowIsMinimized) { -// currentState.render(); - TeraRusty.dispatch(); - } - - lwjglDisplay.update(); - int frameLimit = context.get(Config.class).getRendering().getFrameLimit(); - if (frameLimit > 0) { - Lwjgl2Sync.sync(frameLimit); - } - if (lwjglDisplay.isCloseRequested()) { - engine.shutdown(); - } - } - - @Override - public void preShutdown() { -// long window = GLFW.glfwGetCurrentContext(); - if (primaryWindow != MemoryUtil.NULL) { - boolean isVisible = GLFW.glfwGetWindowAttrib(primaryWindow, GLFW.GLFW_VISIBLE) == GLFW.GLFW_TRUE; - boolean isFullScreen = lwjglDisplay.isFullscreen(); - if (!isFullScreen && isVisible) { - int[] xBuffer = new int[1]; - int[] yBuffer = new int[1]; - GLFW.glfwGetWindowPos(primaryWindow, xBuffer, yBuffer); - int[] widthBuffer = new int[1]; - int[] heightBuffer = new int[1]; - GLFW.glfwGetWindowSize(primaryWindow, widthBuffer, heightBuffer); - - if (widthBuffer[0] > 0 && heightBuffer[0] > 0 && xBuffer[0] > 0 && yBuffer[0] > 0) { - config.setWindowWidth(widthBuffer[0]); - config.setWindowHeight(heightBuffer[0]); - config.setWindowPosX(xBuffer[0]); - config.setWindowPosY(yBuffer[0]); - } - } - } - } - - @Override - public void shutdown() { - GLFW.glfwTerminate(); - } - - private void initGLFW() { if (!GLFW.glfwInit()) { throw new RuntimeException("Failed to initialize GLFW"); } @@ -133,15 +77,10 @@ private void initGLFW() { GLFW.glfwWindowHint(GLFW.GLFW_COCOA_GRAPHICS_SWITCHING, GLFW.GLFW_TRUE); GLFW.glfwWindowHint(GLFW.GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW.GLFW_FALSE); GLFW.glfwWindowHint(GLFW.GLFW_DEPTH_BITS, config.getPixelFormat()); - if (config.getDebug().isEnabled()) { GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_DEBUG_CONTEXT, GLFW.GLFW_TRUE); } - GLFW.glfwSetErrorCallback(new GLFWErrorCallback()); - } - - private void initWindow() { logger.info("Initializing display (if last line in log then likely the game crashed from an issue with your " + "video card)"); @@ -150,19 +89,20 @@ private void initWindow() { switch(GLFW.glfwGetPlatform()) { case GLFW.GLFW_PLATFORM_X11: - TeraRusty.initializeWindowX11(GLFWNativeX11.glfwGetX11Display(), + kernel.initializeWinX11Surface(GLFWNativeX11.glfwGetX11Display(), GLFWNativeX11.glfwGetX11Window(window)); break; default: throw new RuntimeException("missing platform: " + GLFW.glfwGetPlatform()); } + if (window == 0) { throw new RuntimeException("Failed to create window"); } primaryWindow = window; - TeraRusty.windowSizeChanged(lwjglDisplay.getWidth(), lwjglDisplay.getHeight()); + kernel.resizeSurface(lwjglDisplay.getWidth(), lwjglDisplay.getHeight()); if (OS.get() != OS.MACOSX) { try { String root = "org/terasology/engine/icons/"; @@ -186,17 +126,70 @@ private void initWindow() { } lwjglDisplay.setDisplayModeSetting(config.getDisplayModeSetting(), false); - GLFW.glfwShowWindow(window); - } - - private void initOpenGL() { GLFW.glfwSetFramebufferSizeCallback(LwjglGraphics.primaryWindow, new GLFWFramebufferSizeCallback() { @Override public void invoke(long window, int width, int height) { lwjglDisplay.updateViewport(width, height); - TeraRusty.windowSizeChanged(width, height); + kernel.resizeSurface(width, height); } }); + + context.put(ShaderManager.class, new ShaderManagerLwjgl()); + context.put(CanvasRenderer.class, new LwjglCanvasRenderer(context)); + } + + @Override + public void postUpdate(GameState currentState, float delta) { + graphics.processActions(); + + boolean gameWindowIsMinimized = GLFW.glfwGetWindowAttrib(LwjglGraphics.primaryWindow, GLFW.GLFW_ICONIFIED) == GLFW.GLFW_TRUE; + if (!gameWindowIsMinimized) { +// currentState.render(); +// TeraRusty.dispatch(); + } + + lwjglDisplay.update(); + int frameLimit = context.get(Config.class).getRendering().getFrameLimit(); + if (frameLimit > 0) { + Lwjgl2Sync.sync(frameLimit); + } + if (lwjglDisplay.isCloseRequested()) { + engine.shutdown(); + } } + + @Override + public void preShutdown() { +// long window = GLFW.glfwGetCurrentContext(); + if (primaryWindow != MemoryUtil.NULL) { + boolean isVisible = GLFW.glfwGetWindowAttrib(primaryWindow, GLFW.GLFW_VISIBLE) == GLFW.GLFW_TRUE; + boolean isFullScreen = lwjglDisplay.isFullscreen(); + if (!isFullScreen && isVisible) { + int[] xBuffer = new int[1]; + int[] yBuffer = new int[1]; + GLFW.glfwGetWindowPos(primaryWindow, xBuffer, yBuffer); + int[] widthBuffer = new int[1]; + int[] heightBuffer = new int[1]; + GLFW.glfwGetWindowSize(primaryWindow, widthBuffer, heightBuffer); + + if (widthBuffer[0] > 0 && heightBuffer[0] > 0 && xBuffer[0] > 0 && yBuffer[0] > 0) { + config.setWindowWidth(widthBuffer[0]); + config.setWindowHeight(heightBuffer[0]); + config.setWindowPosX(xBuffer[0]); + config.setWindowPosY(yBuffer[0]); + } + } + } + } + + @Override + public void shutdown() { + GLFW.glfwTerminate(); + } + + private void initWindow() { + + } + } diff --git a/facades/PC/src/main/java/org/terasology/engine/Terasology.java b/facades/PC/src/main/java/org/terasology/engine/Terasology.java index 433380f9f00..28246f82b4a 100644 --- a/facades/PC/src/main/java/org/terasology/engine/Terasology.java +++ b/facades/PC/src/main/java/org/terasology/engine/Terasology.java @@ -163,7 +163,7 @@ public Integer call() throws IOException { } splashScreen.post("Java Runtime " + System.getProperty("java.version") + " loaded"); - try { +// try { TerasologyEngineBuilder builder = new TerasologyEngineBuilder(); populateSubsystems(builder); TerasologyEngine engine = builder.build(); @@ -187,12 +187,12 @@ public Integer call() throws IOException { } engine.run(nextState); - } catch (Throwable e) { - // also catch Errors such as UnsatisfiedLink, NoSuchMethodError, etc. - splashScreen.close(); - reportException(e); - return 1; - } +// } catch (Throwable e) { +// // also catch Errors such as UnsatisfiedLink, NoSuchMethodError, etc. +// splashScreen.close(); +// reportException(e); +// return 1; +// } return 0; } From 7a8b6c41dbde686fd0e2315745129a4e186869a9 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 11 Jul 2023 23:10:55 -0700 Subject: [PATCH 04/13] feat: cleanup api Signed-off-by: Michael Pollind --- .../org/terasology/engine/core/TerasologyEngine.java | 6 ++---- .../engine/core/subsystem/lwjgl/LwjglGraphics.java | 10 +++++----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/engine/src/main/java/org/terasology/engine/core/TerasologyEngine.java b/engine/src/main/java/org/terasology/engine/core/TerasologyEngine.java index dec334b0aa7..2fd0a9f6670 100644 --- a/engine/src/main/java/org/terasology/engine/core/TerasologyEngine.java +++ b/engine/src/main/java/org/terasology/engine/core/TerasologyEngine.java @@ -122,7 +122,6 @@ public class TerasologyEngine implements GameEngine { private Set stateChangeSubscribers = Sets.newLinkedHashSet(); private EngineStatus status = StandardGameStatus.UNSTARTED; - private EngineKernel kernel; private final List statusSubscriberList = new CopyOnWriteArrayList<>(); private volatile boolean shutdownRequested; @@ -164,8 +163,7 @@ public TerasologyEngine(TimeSubsystem timeSubsystem, Collection DirectionAndOriginPosRecorderList directionAndOriginPosRecorderList = new DirectionAndOriginPosRecorderList(); rootContext.put(DirectionAndOriginPosRecorderList.class, directionAndOriginPosRecorderList); - kernel = new EngineKernel(); - rootContext.put(EngineKernel.class, kernel); + EngineKernel.initialize(); /* * We can't load the engine without core registry yet. * e.g. the statically created MaterialLoader needs the CoreRegistry to get the AssetManager. @@ -561,7 +559,7 @@ public void cleanup() { logger.error("Error shutting down {} subsystem", subsystem.getName(), e); } } - kernel.dispose(); + EngineKernel.disposeKernel(); } /** diff --git a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java index 1d7b3a1cc3e..b6ec8389e51 100644 --- a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java +++ b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java @@ -38,7 +38,7 @@ public class LwjglGraphics extends BaseLwjglSubsystem { private GameEngine engine; private LwjglDisplayDevice lwjglDisplay; - private EngineKernel kernel; +// private EngineKernel kernel; private LwjglGraphicsManager graphics = new LwjglGraphicsManager(); @@ -66,7 +66,7 @@ public void registerCoreAssetTypes(ModuleAwareAssetTypeManager assetTypeManager) @Override public void postInitialise(Context rootContext) { graphics.registerRenderingSubsystem(context); - this.kernel = context.get(EngineKernel.class); +// this.kernel = context.get(EngineKernel.class); if (!GLFW.glfwInit()) { throw new RuntimeException("Failed to initialize GLFW"); @@ -89,7 +89,7 @@ public void postInitialise(Context rootContext) { switch(GLFW.glfwGetPlatform()) { case GLFW.GLFW_PLATFORM_X11: - kernel.initializeWinX11Surface(GLFWNativeX11.glfwGetX11Display(), + EngineKernel.instance().initializeWinX11Surface(GLFWNativeX11.glfwGetX11Display(), GLFWNativeX11.glfwGetX11Window(window)); break; default: @@ -102,7 +102,7 @@ public void postInitialise(Context rootContext) { } primaryWindow = window; - kernel.resizeSurface(lwjglDisplay.getWidth(), lwjglDisplay.getHeight()); + EngineKernel.instance().resizeSurface(lwjglDisplay.getWidth(), lwjglDisplay.getHeight()); if (OS.get() != OS.MACOSX) { try { String root = "org/terasology/engine/icons/"; @@ -131,7 +131,7 @@ public void postInitialise(Context rootContext) { @Override public void invoke(long window, int width, int height) { lwjglDisplay.updateViewport(width, height); - kernel.resizeSurface(width, height); + EngineKernel.instance().resizeSurface(width, height); } }); From 1e3885e95ec0d30d077b1a3db2919a3a7d8afa78 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Fri, 14 Jul 2023 07:21:13 -0700 Subject: [PATCH 05/13] add dispatch logic Signed-off-by: Michael Pollind --- .../engine/core/subsystem/lwjgl/LwjglGraphics.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java index b6ec8389e51..41be385f98e 100644 --- a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java +++ b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java @@ -145,8 +145,10 @@ public void postUpdate(GameState currentState, float delta) { boolean gameWindowIsMinimized = GLFW.glfwGetWindowAttrib(LwjglGraphics.primaryWindow, GLFW.GLFW_ICONIFIED) == GLFW.GLFW_TRUE; if (!gameWindowIsMinimized) { -// currentState.render(); -// TeraRusty.dispatch(); + EngineKernel kernel = EngineKernel.instance(); + kernel.cmdPrepare(); + currentState.render(); + kernel.cmdDispatch(); } lwjglDisplay.update(); From 9c0c1c7cfb622e4a9d51adc7bab84412cd07e1cf Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Mon, 17 Jul 2023 22:05:58 -0700 Subject: [PATCH 06/13] feat: add wgpu texture Signed-off-by: Michael Pollind --- .../core/subsystem/lwjgl/LwjglGraphics.java | 4 +- .../subsystem/lwjgl/LwjglGraphicsManager.java | 5 +- .../nui/internal/WgpuCanvasRenderer.java | 106 +++++++++++++ .../opengl/LwjglFrameBufferObject.java | 2 - .../rendering/opengl/OpenGLTexture.java | 144 +++++++++--------- .../engine/rendering/opengl/WgpuTexture.java | 138 +++++++++++++++++ 6 files changed, 322 insertions(+), 77 deletions(-) create mode 100644 engine/src/main/java/org/terasology/engine/rendering/nui/internal/WgpuCanvasRenderer.java create mode 100644 engine/src/main/java/org/terasology/engine/rendering/opengl/WgpuTexture.java diff --git a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java index 41be385f98e..7b86d846124 100644 --- a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java +++ b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java @@ -17,7 +17,7 @@ import org.terasology.engine.core.subsystem.DisplayDevice; import org.terasology.engine.rendering.ShaderManager; import org.terasology.engine.rendering.ShaderManagerLwjgl; -import org.terasology.engine.rendering.nui.internal.LwjglCanvasRenderer; +import org.terasology.engine.rendering.nui.internal.WgpuCanvasRenderer; import org.terasology.engine.rust.EngineKernel; import org.terasology.engine.utilities.OS; import org.terasology.gestalt.assets.module.ModuleAwareAssetTypeManager; @@ -136,7 +136,7 @@ public void invoke(long window, int width, int height) { }); context.put(ShaderManager.class, new ShaderManagerLwjgl()); - context.put(CanvasRenderer.class, new LwjglCanvasRenderer(context)); + context.put(CanvasRenderer.class, new WgpuCanvasRenderer(context)); } @Override diff --git a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphicsManager.java b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphicsManager.java index 65254d625ab..5a6bed45dc3 100644 --- a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphicsManager.java +++ b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphicsManager.java @@ -29,6 +29,7 @@ import org.terasology.engine.rendering.opengl.OpenGLMesh; import org.terasology.engine.rendering.opengl.OpenGLSkeletalMesh; import org.terasology.engine.rendering.opengl.OpenGLTexture; +import org.terasology.engine.rendering.opengl.WgpuTexture; import org.terasology.gestalt.assets.AssetType; import org.terasology.gestalt.assets.module.ModuleAssetScanner; import org.terasology.gestalt.assets.module.ModuleAwareAssetTypeManager; @@ -61,8 +62,10 @@ public void registerCoreAssetTypes(ModuleAwareAssetTypeManager assetTypeManager) // cast lambdas explicitly to avoid inconsistent compiler behavior wrt. type inference assetTypeManager.createAssetType(Font.class, FontImpl::new, "fonts"); + //AssetType texture = assetTypeManager.createAssetType(Texture.class, + // (urn, assetType, data) -> (OpenGLTexture.create(urn, assetType, data, this)), "textures", "fonts"); AssetType texture = assetTypeManager.createAssetType(Texture.class, - (urn, assetType, data) -> (OpenGLTexture.create(urn, assetType, data, this)), "textures", "fonts"); + WgpuTexture::create, "textures", "fonts"); assetTypeManager.getAssetFileDataProducer(texture).addAssetFormat( new PNGTextureFormat(Texture.FilterMode.NEAREST, path -> { diff --git a/engine/src/main/java/org/terasology/engine/rendering/nui/internal/WgpuCanvasRenderer.java b/engine/src/main/java/org/terasology/engine/rendering/nui/internal/WgpuCanvasRenderer.java new file mode 100644 index 00000000000..397100ea335 --- /dev/null +++ b/engine/src/main/java/org/terasology/engine/rendering/nui/internal/WgpuCanvasRenderer.java @@ -0,0 +1,106 @@ +// Copyright 2023 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.engine.rendering.nui.internal; + +import org.joml.Quaternionfc; +import org.joml.Vector2fc; +import org.joml.Vector2i; +import org.joml.Vector2ic; +import org.joml.Vector3fc; +import org.terasology.engine.context.Context; +import org.terasology.engine.core.subsystem.DisplayDevice; +import org.terasology.engine.rendering.assets.material.Material; +import org.terasology.engine.rendering.assets.mesh.Mesh; +import org.terasology.engine.rendering.opengl.FrameBufferObject; +import org.terasology.engine.rendering.opengl.WgpuTexture; +import org.terasology.engine.rust.EngineKernel; +import org.terasology.gestalt.assets.ResourceUrn; +import org.terasology.joml.geom.Rectanglef; +import org.terasology.joml.geom.Rectanglei; +import org.terasology.nui.Border; +import org.terasology.nui.Colorc; +import org.terasology.nui.HorizontalAlign; +import org.terasology.nui.ScaleMode; +import org.terasology.nui.UITextureRegion; +import org.terasology.nui.VerticalAlign; +import org.terasology.nui.asset.font.Font; + +public class WgpuCanvasRenderer implements TerasologyCanvasRenderer { + private DisplayDevice displayDevice; + + public WgpuCanvasRenderer(Context context) { + this.displayDevice = context.get(DisplayDevice.class); + } + + @Override + public void preRender() { + + } + + @Override + public void postRender() { + + } + + @Override + public Vector2i getTargetSize() { + return new Vector2i(displayDevice.getWidth(), displayDevice.getHeight()); + } + + @Override + public void crop(Rectanglei cropRegion) { + EngineKernel kernel = EngineKernel.instance(); + + } + + @Override + public void drawLine(int sx, int sy, int ex, int ey, Colorc color) { + + } + + @Override + public void drawTexture(UITextureRegion texture, Colorc color, ScaleMode mode, Rectanglei absoluteRegion, float ux, float uy, float uw, float uh, float alpha) { + EngineKernel kernel = EngineKernel.instance(); + if(texture instanceof WgpuTexture) { + Vector2fc size = ((WgpuTexture) texture).getTeraTexture().getSize(); + + kernel.cmdUIDrawTexture( + ((WgpuTexture) texture).getTeraTexture(), + new Rectanglef(ux, uy , ux + uw, uy + uh), + new Rectanglef(absoluteRegion.minX(), absoluteRegion.minY(), absoluteRegion.maxX(), absoluteRegion.maxY())); +// ((WgpuTexture) texture).getTexture() + } + + } + + @Override + public void drawText(String text, Font font, HorizontalAlign hAlign, VerticalAlign vAlign, Rectanglei absoluteRegion, Colorc color, Colorc shadowColor, float alpha, boolean underlined) { + + } + + @Override + public void drawTextureBordered(UITextureRegion texture, Rectanglei absoluteRegion, Border border, boolean tile, float ux, float uy, float uw, float uh, float alpha) { + + } + + @Override + public void setUiScale(float uiScale) { + + } + + @Override + public FrameBufferObject getFBO(ResourceUrn urn, Vector2ic size) { + return null; + } + + @Override + public void drawMesh(Mesh mesh, Material material, Rectanglei drawRegion, Rectanglei cropRegion, Quaternionfc rotation, Vector3fc offset, float scale, float alpha) { + + } + + @Override + public void drawMaterialAt(Material material, Rectanglei drawRegion) { + + } +} diff --git a/engine/src/main/java/org/terasology/engine/rendering/opengl/LwjglFrameBufferObject.java b/engine/src/main/java/org/terasology/engine/rendering/opengl/LwjglFrameBufferObject.java index 19dc3916485..b8b81260ced 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/opengl/LwjglFrameBufferObject.java +++ b/engine/src/main/java/org/terasology/engine/rendering/opengl/LwjglFrameBufferObject.java @@ -12,7 +12,6 @@ import org.terasology.engine.core.subsystem.DisplayDevice; import org.terasology.engine.rendering.assets.texture.Texture; import org.terasology.engine.rendering.assets.texture.TextureData; -import org.terasology.engine.rendering.nui.internal.LwjglCanvasRenderer; import org.terasology.engine.utilities.Assets; import org.terasology.gestalt.assets.ResourceUrn; @@ -27,7 +26,6 @@ public class LwjglFrameBufferObject implements FrameBufferObject { private int frame; private Vector2ic size; private IntBuffer vp; - private LwjglCanvasRenderer canvasRenderer; private final Matrix4fStack transforms; private final Matrix4f projectionMatrix; diff --git a/engine/src/main/java/org/terasology/engine/rendering/opengl/OpenGLTexture.java b/engine/src/main/java/org/terasology/engine/rendering/opengl/OpenGLTexture.java index f807287bda5..13a89423715 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/opengl/OpenGLTexture.java +++ b/engine/src/main/java/org/terasology/engine/rendering/opengl/OpenGLTexture.java @@ -41,78 +41,78 @@ public void setId(int id) { @Override protected void doReload(TextureData data) { -// switch (data.getType()) { -// // TODO: reconsider how 3D textures handled (probably separate asset implementation with common interface? -// case TEXTURE3D: -// if (data.getWidth() % data.getHeight() != 0 || data.getWidth() / data.getHeight() != data.getHeight()) { -// throw new RuntimeException("3D texture must be cubic (height^3) - width must thus be a multiple of height"); -// } -// int size = data.getHeight(); -// -// final int byteLength = 4 * 16 * 16 * 16; -// final int strideX = 16 * 4; -// final int strideY = 16 * 16 * 4; -// final int strideZ = 4; -// -// ByteBuffer alignedBuffer = ByteBuffer.allocateDirect(byteLength); -// for (int x = 0; x < size; x++) { -// for (int y = 0; y < size; y++) { -// for (int z = 0; z < size; z++) { -// final int index = x * strideX + z * strideZ + strideY * y; -// -// alignedBuffer.put(data.getBuffers()[0].get(index)); -// alignedBuffer.put(data.getBuffers()[0].get(index + 1)); -// alignedBuffer.put(data.getBuffers()[0].get(index + 2)); -// alignedBuffer.put(data.getBuffers()[0].get(index + 3)); -// } -// } -// } -// alignedBuffer.flip(); -// -// resources.loadedTextureInfo = new LoadedTextureInfo(size, size, size, data); -// -// if (resources.id == 0) { -// resources.graphicsManager.createTexture3D(alignedBuffer, getWrapMode(), getFilterMode(), -// size, (newId) -> { -// synchronized (this) { -// if (resources.id != 0) { -// resources.graphicsManager.disposeTexture(resources.id); -// } -// if (isDisposed()) { -// resources.graphicsManager.disposeTexture(newId); -// } else { -// resources.id = newId; -// logger.debug("Bound texture '{}' - {}", getUrn(), resources.id); -// } -// } -// }); -// } else { -// resources.graphicsManager.reloadTexture3D(resources.id, alignedBuffer, getWrapMode(), getFilterMode(), size); -// } -// break; -// default: -// int width = data.getWidth(); -// int height = data.getHeight(); -// resources.loadedTextureInfo = new LoadedTextureInfo(width, height, 1, data); -// if (resources.id == 0) { -// resources.graphicsManager.createTexture2D(data.getBuffers(), getWrapMode(), getFilterMode(), width, height, (newId) -> { -// synchronized (this) { -// if (resources.id != 0) { -// resources.graphicsManager.disposeTexture(resources.id); -// } -// if (isDisposed()) { -// resources.graphicsManager.disposeTexture(newId); -// } else { -// resources.id = newId; -// logger.debug("Bound texture '{}' - {}", getUrn(), resources.id); -// } -// } -// }); -// } else { -// resources.graphicsManager.reloadTexture2D(resources.id, data.getBuffers(), getWrapMode(), getFilterMode(), width, height); -// } -// break; -// } + switch (data.getType()) { + // TODO: reconsider how 3D textures handled (probably separate asset implementation with common interface? + case TEXTURE3D: + if (data.getWidth() % data.getHeight() != 0 || data.getWidth() / data.getHeight() != data.getHeight()) { + throw new RuntimeException("3D texture must be cubic (height^3) - width must thus be a multiple of height"); + } + int size = data.getHeight(); + + final int byteLength = 4 * 16 * 16 * 16; + final int strideX = 16 * 4; + final int strideY = 16 * 16 * 4; + final int strideZ = 4; + + ByteBuffer alignedBuffer = ByteBuffer.allocateDirect(byteLength); + for (int x = 0; x < size; x++) { + for (int y = 0; y < size; y++) { + for (int z = 0; z < size; z++) { + final int index = x * strideX + z * strideZ + strideY * y; + + alignedBuffer.put(data.getBuffers()[0].get(index)); + alignedBuffer.put(data.getBuffers()[0].get(index + 1)); + alignedBuffer.put(data.getBuffers()[0].get(index + 2)); + alignedBuffer.put(data.getBuffers()[0].get(index + 3)); + } + } + } + alignedBuffer.flip(); + + resources.loadedTextureInfo = new LoadedTextureInfo(size, size, size, data); + + if (resources.id == 0) { + resources.graphicsManager.createTexture3D(alignedBuffer, getWrapMode(), getFilterMode(), + size, (newId) -> { + synchronized (this) { + if (resources.id != 0) { + resources.graphicsManager.disposeTexture(resources.id); + } + if (isDisposed()) { + resources.graphicsManager.disposeTexture(newId); + } else { + resources.id = newId; + logger.debug("Bound texture '{}' - {}", getUrn(), resources.id); + } + } + }); + } else { + resources.graphicsManager.reloadTexture3D(resources.id, alignedBuffer, getWrapMode(), getFilterMode(), size); + } + break; + default: + int width = data.getWidth(); + int height = data.getHeight(); + resources.loadedTextureInfo = new LoadedTextureInfo(width, height, 1, data); + if (resources.id == 0) { + resources.graphicsManager.createTexture2D(data.getBuffers(), getWrapMode(), getFilterMode(), width, height, (newId) -> { + synchronized (this) { + if (resources.id != 0) { + resources.graphicsManager.disposeTexture(resources.id); + } + if (isDisposed()) { + resources.graphicsManager.disposeTexture(newId); + } else { + resources.id = newId; + logger.debug("Bound texture '{}' - {}", getUrn(), resources.id); + } + } + }); + } else { + resources.graphicsManager.reloadTexture2D(resources.id, data.getBuffers(), getWrapMode(), getFilterMode(), width, height); + } + break; + } } @Override diff --git a/engine/src/main/java/org/terasology/engine/rendering/opengl/WgpuTexture.java b/engine/src/main/java/org/terasology/engine/rendering/opengl/WgpuTexture.java new file mode 100644 index 00000000000..10b06571a1b --- /dev/null +++ b/engine/src/main/java/org/terasology/engine/rendering/opengl/WgpuTexture.java @@ -0,0 +1,138 @@ +// Copyright 2023 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.engine.rendering.opengl; + +import com.google.common.collect.Lists; +import org.joml.Vector2i; +import org.terasology.engine.rendering.assets.texture.Texture; +import org.terasology.engine.rendering.assets.texture.TextureData; +import org.terasology.engine.rust.TeraTexture; +import org.terasology.gestalt.assets.AssetType; +import org.terasology.gestalt.assets.DisposableResource; +import org.terasology.gestalt.assets.ResourceUrn; +import org.terasology.joml.geom.Rectanglef; +import org.terasology.joml.geom.Rectanglei; + +import java.util.List; + + +public class WgpuTexture extends Texture { + + private TextureResources resource; + + private static TeraTexture.TextureDesc createDesc(TextureData data) { + TeraTexture.TextureDesc desc = new TeraTexture.TextureDesc(); + desc.format = TeraTexture.ImageFormat.R8G8B8A8_UNORM; + desc.dim = TeraTexture.TextureDimension.DIM_2D; + desc.width = data.getWidth(); + desc.height = data.getHeight(); + desc.layers = 1; + return desc; + } + + public WgpuTexture(ResourceUrn urn, AssetType assetType, TextureResources textureResources) { + super(urn, assetType); + this.resource = textureResources; + } + + public static WgpuTexture create(ResourceUrn urn, AssetType assetType, TextureData data) { + return new WgpuTexture(urn, assetType, new TextureResources(data, TeraTexture.createFromBuffer(createDesc(data), data.getBuffers()[0]))); + } + + @Override + protected void doReload(TextureData data) { + this.resource = new TextureResources(data, TeraTexture.createFromBuffer(createDesc(data), data.getBuffers()[0])); + } + + @Override + public WrapMode getWrapMode() { + return WrapMode.CLAMP; + } + + @Override + public FilterMode getFilterMode() { + return FilterMode.NEAREST; + } + + @Override + public TextureData getData() { + return this.resource.data; + } + + @Override + public int getId() { + return 0; + } + + @Override + public int getDepth() { + return 1; + } + + @Override + public boolean isLoaded() { + return true; + } + + @Override + public void subscribeToDisposal(DisposableResource subscriber) { + this.resource.disposalSubscribers.add(subscriber); + } + + @Override + public void unsubscribeToDisposal(DisposableResource subscriber) { + this.resource.disposalSubscribers.remove(subscriber); + } + + @Override + public Texture getTexture() { + return this; + } + + @Override + public Rectanglef getRegion() { + return new Rectanglef(FULL_TEXTURE_REGION); // object is not guarded + } + + @Override + public Rectanglei getPixelRegion() { + return new Rectanglei(0, 0, getWidth(), getHeight()); + } + + @Override + public int getWidth() { + return this.resource.data.getWidth(); + } + + @Override + public int getHeight() { + return this.resource.data.getHeight(); + } + + @Override + public Vector2i size() { + return new Vector2i(this.resource.data.getWidth(), this.resource.data.getHeight()); + } + + public TeraTexture getTeraTexture() { + return this.resource.texture; + } + + private static class TextureResources implements DisposableResource { + private final TeraTexture texture; + private final List disposalSubscribers = Lists.newArrayList(); + private final TextureData data; + + TextureResources(TextureData data, TeraTexture texture) { + this.data = data; + this.texture = texture; + } + + @Override + public void close() { + disposalSubscribers.forEach(DisposableResource::close); + this.texture.dispose(); + } + } +} From 5573436dd8eef2f31da038833933c8d1f5d33de4 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 18 Jul 2023 22:32:44 -0700 Subject: [PATCH 07/13] feat: added logic to draw borderer images Signed-off-by: Michael Pollind --- .../core/subsystem/lwjgl/LwjglGraphics.java | 6 + .../nui/internal/WgpuCanvasRenderer.java | 230 +++++++++++++++++- 2 files changed, 234 insertions(+), 2 deletions(-) diff --git a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java index 7b86d846124..598b6d698af 100644 --- a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java +++ b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java @@ -5,6 +5,7 @@ import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFWFramebufferSizeCallback; import org.lwjgl.glfw.GLFWImage; +import org.lwjgl.glfw.GLFWNativeWin32; import org.lwjgl.glfw.GLFWNativeX11; import org.lwjgl.system.MemoryUtil; import org.slf4j.Logger; @@ -92,6 +93,11 @@ public void postInitialise(Context rootContext) { EngineKernel.instance().initializeWinX11Surface(GLFWNativeX11.glfwGetX11Display(), GLFWNativeX11.glfwGetX11Window(window)); break; + case GLFW.GLFW_PLATFORM_WIN32: + EngineKernel.instance().initializeWin32Surface( + GLFWNativeWin32.nglfwGetWin32Adapter(window), + GLFWNativeWin32.glfwGetWin32Window(window)); + break; default: throw new RuntimeException("missing platform: " + GLFW.glfwGetPlatform()); } diff --git a/engine/src/main/java/org/terasology/engine/rendering/nui/internal/WgpuCanvasRenderer.java b/engine/src/main/java/org/terasology/engine/rendering/nui/internal/WgpuCanvasRenderer.java index 397100ea335..50d0d37b2f1 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/nui/internal/WgpuCanvasRenderer.java +++ b/engine/src/main/java/org/terasology/engine/rendering/nui/internal/WgpuCanvasRenderer.java @@ -10,21 +10,31 @@ import org.joml.Vector3fc; import org.terasology.engine.context.Context; import org.terasology.engine.core.subsystem.DisplayDevice; +import org.terasology.engine.rendering.assets.font.FontCharacter; import org.terasology.engine.rendering.assets.material.Material; import org.terasology.engine.rendering.assets.mesh.Mesh; +import org.terasology.engine.rendering.assets.mesh.MeshBuilder; import org.terasology.engine.rendering.opengl.FrameBufferObject; import org.terasology.engine.rendering.opengl.WgpuTexture; import org.terasology.engine.rust.EngineKernel; import org.terasology.gestalt.assets.ResourceUrn; import org.terasology.joml.geom.Rectanglef; import org.terasology.joml.geom.Rectanglei; +import org.terasology.math.TeraMath; import org.terasology.nui.Border; import org.terasology.nui.Colorc; +import org.terasology.nui.FontColor; +import org.terasology.nui.FontUnderline; import org.terasology.nui.HorizontalAlign; import org.terasology.nui.ScaleMode; +import org.terasology.nui.TextLineBuilder; import org.terasology.nui.UITextureRegion; import org.terasology.nui.VerticalAlign; import org.terasology.nui.asset.font.Font; +import reactor.function.Consumer4; +import reactor.function.Consumer5; + +import java.util.List; public class WgpuCanvasRenderer implements TerasologyCanvasRenderer { private DisplayDevice displayDevice; @@ -62,14 +72,13 @@ public void drawLine(int sx, int sy, int ex, int ey, Colorc color) { @Override public void drawTexture(UITextureRegion texture, Colorc color, ScaleMode mode, Rectanglei absoluteRegion, float ux, float uy, float uw, float uh, float alpha) { EngineKernel kernel = EngineKernel.instance(); - if(texture instanceof WgpuTexture) { + if (texture instanceof WgpuTexture) { Vector2fc size = ((WgpuTexture) texture).getTeraTexture().getSize(); kernel.cmdUIDrawTexture( ((WgpuTexture) texture).getTeraTexture(), new Rectanglef(ux, uy , ux + uw, uy + uh), new Rectanglef(absoluteRegion.minX(), absoluteRegion.minY(), absoluteRegion.maxX(), absoluteRegion.maxY())); -// ((WgpuTexture) texture).getTexture() } } @@ -77,11 +86,228 @@ public void drawTexture(UITextureRegion texture, Colorc color, ScaleMode mode, R @Override public void drawText(String text, Font font, HorizontalAlign hAlign, VerticalAlign vAlign, Rectanglei absoluteRegion, Colorc color, Colorc shadowColor, float alpha, boolean underlined) { + EngineKernel kernel = EngineKernel.instance(); + + List lines = TextLineBuilder.getLines(font, text, absoluteRegion.getSizeX()); + Vector2i offset = new Vector2i(absoluteRegion.minX, absoluteRegion.minY); + offset.y += vAlign.getOffset(lines.size() * font.getLineHeight(), absoluteRegion.lengthY()); + + org.terasology.engine.rendering.assets.font.Font + fnt = (org.terasology.engine.rendering.assets.font.Font) font; + int y = 0; + + for (String line : lines) { + int w = font.getWidth(line); + int x = hAlign.getOffset(w, absoluteRegion.getSizeX()); + for (char c : line.toCharArray()) { + FontCharacter character = fnt.getCharacterData(c); + float top = y + character.getyOffset(); + float bottom = top + character.getHeight(); + float left = x + character.getxOffset(); + float right = left + character.getWidth(); + + float texTop = character.getY(); + float texBottom = texTop + character.getTexHeight(); + float texLeft = character.getX(); + float texRight = texLeft + character.getTexWidth(); + + kernel.cmdUIDrawTexture( + ((WgpuTexture) character.getPage()).getTeraTexture(), + new Rectanglef(texLeft, texTop, texRight, texBottom), + new Rectanglef(left + offset.x, top + offset.y, right + offset.x, bottom + offset.y)); + x += character.getxAdvance(); + } + y += font.getLineHeight(); + } } + @Override public void drawTextureBordered(UITextureRegion texture, Rectanglei absoluteRegion, Border border, boolean tile, float ux, float uy, float uw, float uh, float alpha) { + EngineKernel kernel = EngineKernel.instance(); + Vector2i textureSize = new Vector2i(TeraMath.ceilToInt(texture.getWidth() * uw), + TeraMath.ceilToInt(texture.getHeight() * uh)); + Rectanglei region = new Rectanglei(absoluteRegion); + + if (texture instanceof WgpuTexture) { + Consumer4 cmdDrawTiles = (Rectanglei drawRegion, Rectanglef subDrawRegion, Vector2i tileSize, + Rectanglef subTextureRegion) -> { + int tileW = tileSize.x; + int tileH = tileSize.y; + int horizTiles = TeraMath.fastAbs((drawRegion.getSizeX() - 1) / tileW) + 1; + int vertTiles = TeraMath.fastAbs((drawRegion.getSizeY() - 1) / tileH) + 1; + + int offsetX = (drawRegion.getSizeX() - horizTiles * tileW) / 2; + int offsetY = (drawRegion.getSizeY() - vertTiles * tileH) / 2; + for (int tileY = 0; tileY < vertTiles; tileY++) { + for (int tileX = 0; tileX < horizTiles; tileX++) { + int left = offsetX + tileW * tileX; + int top = offsetY + tileH * tileY; + + float vertLeft = + subDrawRegion.minX + subDrawRegion.getSizeX() * Math.max((float) left / drawRegion.getSizeX(), 0); + float vertTop = + subDrawRegion.minY + subDrawRegion.getSizeY() * Math.max((float) top / drawRegion.getSizeY(), 0); + float vertRight = + subDrawRegion.minX + subDrawRegion.getSizeX() * Math.min((float) (left + tileW) / drawRegion.getSizeX(), 1); + float vertBottom = + subDrawRegion.minY + subDrawRegion.getSizeY() * Math.min((float) (top + tileH) / drawRegion.getSizeY(), 1); + float texCoordLeft = + subTextureRegion.minX + subTextureRegion.getSizeX() * (Math.max(left, 0) - left) / tileW; + float texCoordTop = + subTextureRegion.minY + subTextureRegion.getSizeY() * (Math.max(top, 0) - top) / tileH; + float texCoordRight = subTextureRegion.minX + subTextureRegion.getSizeX() * (Math.min(left + tileW, + drawRegion.getSizeX()) - left) / tileW; + float texCoordBottom = subTextureRegion.minY + subTextureRegion.getSizeY() * (Math.min(top + tileH, + drawRegion.getSizeY()) - top) / tileH; + kernel.cmdUIDrawTexture( + ((WgpuTexture) texture).getTeraTexture(), + new Rectanglef(texCoordLeft, texCoordTop, texCoordRight, texCoordBottom), + new Rectanglef( vertLeft, vertTop, vertRight, vertBottom) + .scale(region.getSizeX(), region.getSizeY()) + .translate(region.minX, region.minY)); +// addRectPoly(builder, vertLeft, vertTop, vertRight, vertBottom, texCoordLeft, texCoordTop, +// texCoordRight, texCoordBottom); + } + } + }; + + float topTex = (float) border.getTop() / textureSize.y; + float leftTex = (float) border.getLeft() / textureSize.x; + float bottomTex = 1f - (float) border.getBottom() / textureSize.y; + float rightTex = 1f - (float) border.getRight() / textureSize.x; + int centerHoriz = region.getSizeX() - border.getTotalWidth(); + int centerVert = region.getSizeY() - border.getTotalHeight(); + + float top = (float) border.getTop() / region.getSizeY(); + float left = (float) border.getLeft() / region.getSizeX(); + float bottom = 1f - (float) border.getBottom() / region.getSizeY(); + float right = 1f - (float) border.getRight() / region.getSizeX(); + + + if (border.getTop() != 0) { + if (border.getLeft() != 0) { + kernel.cmdUIDrawTexture( + ((WgpuTexture) texture).getTeraTexture(), + new Rectanglef(0, 0, leftTex, topTex), + new Rectanglef(0, 0, left, top) + .scale(region.getSizeX(), region.getSizeY()) + .translate(region.minX, region.minY)); + } + if (tile) { + + cmdDrawTiles.accept(new Rectanglei(border.getLeft(), 0).setSize(centerHoriz, border.getTop()), + new Rectanglef(left, 0, right, top), + new Vector2i(textureSize.x - border.getTotalWidth(), border.getTop()), + new Rectanglef(leftTex, 0, rightTex, topTex) + .scale(region.getSizeX(), region.getSizeY()) + .translate(region.minX, region.minY)); + } else { +// addRectPoly(builder, left, 0, right, top, leftTex, 0, rightTex, topTex); + kernel.cmdUIDrawTexture( + ((WgpuTexture) texture).getTeraTexture(), + new Rectanglef(leftTex, 0, rightTex, topTex), + new Rectanglef( left, 0, right, top).translate(region.minX, region.minY) + .scale(region.getSizeX(), region.getSizeY()) + .translate(region.minX, region.minY)); + } + if (border.getRight() != 0) { +// addRectPoly(builder, right, 0, 1, top, rightTex, 0, 1, topTex); + kernel.cmdUIDrawTexture( + ((WgpuTexture) texture).getTeraTexture(), + new Rectanglef(rightTex, 0, 1, topTex), + new Rectanglef(right, 0, 1, top) + .scale(region.getSizeX(), region.getSizeY()) + .translate(region.minX, region.minY)); + } + } + + if (border.getLeft() != 0) { + if (tile) { + cmdDrawTiles.accept(new Rectanglei(0, border.getTop()).setSize(border.getLeft(), centerVert), + new Rectanglef(0, top, left, bottom), + new Vector2i(border.getLeft(), textureSize.y - border.getTotalHeight()), + new Rectanglef(0, topTex, leftTex, bottomTex)); + } else { +// addRectPoly(builder, 0, top, left, bottom, 0, topTex, leftTex, bottomTex); + kernel.cmdUIDrawTexture( + ((WgpuTexture) texture).getTeraTexture(), + new Rectanglef(0, topTex, leftTex, bottomTex), + new Rectanglef( 0, top, left, bottom) + .scale(region.getSizeX(), region.getSizeY()) + .translate(region.minX, region.minY)); + } + } + + if (tile) { + cmdDrawTiles.accept(new Rectanglei(border.getLeft(), border.getTop()).setSize(centerHoriz, centerVert), + new Rectanglef(left, top, right, bottom), + new Vector2i(textureSize.x - border.getTotalWidth(), textureSize.y - border.getTotalHeight()), + new Rectanglef(leftTex, topTex, rightTex, bottomTex)); + } else { +// addRectPoly(builder, left, top, right, bottom, leftTex, topTex, rightTex, bottomTex); + kernel.cmdUIDrawTexture( + ((WgpuTexture) texture).getTeraTexture(), + new Rectanglef(leftTex, topTex, rightTex, bottomTex), + new Rectanglef(left, top, right, bottom) + .scale(region.getSizeX(), region.getSizeY()) + .translate(region.minX, region.minY)); + } + + if (border.getRight() != 0) { + if (tile) { + cmdDrawTiles.accept( + new Rectanglei(region.getSizeX() - border.getRight(), border.getTop()).setSize(border.getRight(), centerVert), + new Rectanglef(right, top, 1, bottom), + new Vector2i(border.getRight(), textureSize.y - border.getTotalHeight()), + new Rectanglef(rightTex, topTex, 1, bottomTex)); + } else { + kernel.cmdUIDrawTexture( + ((WgpuTexture) texture).getTeraTexture(), + new Rectanglef(rightTex, topTex, 1, bottomTex), + new Rectanglef(right, top, 1, bottom) + .scale(region.getSizeX(), region.getSizeY()) + .translate(region.minX, region.minY)); + } + } + + if (border.getBottom() != 0) { + if (border.getLeft() != 0) { +// addRectPoly(builder, 0, bottom, left, 1, 0, bottomTex, leftTex, 1); + kernel.cmdUIDrawTexture( + ((WgpuTexture) texture).getTeraTexture(), + new Rectanglef(0, bottomTex, leftTex, 1), + new Rectanglef(0, bottom, left, 1) + .scale(region.getSizeX(), region.getSizeY()) + .translate(region.minX, region.minY)); + } + if (tile) { + cmdDrawTiles.accept( + new Rectanglei(border.getLeft(), region.getSizeY() - border.getBottom()).setSize(centerHoriz, border.getBottom()), + new Rectanglef(left, bottom, right, 1), + new Vector2i(textureSize.x - border.getTotalWidth(), border.getBottom()), + new Rectanglef(leftTex, bottomTex, rightTex, 1)); + } else { +// addRectPoly(builder, left, bottom, right, 1, leftTex, bottomTex, rightTex, 1); + kernel.cmdUIDrawTexture( + ((WgpuTexture) texture).getTeraTexture(), + new Rectanglef(leftTex, bottomTex, rightTex, 1), + new Rectanglef(left, bottom, right, 1) + .scale(region.getSizeX(), region.getSizeY()) + .translate(region.minX, region.minY)); + } + if (border.getRight() != 0) { +// addRectPoly(builder, right, bottom, 1, 1, rightTex, bottomTex, 1, 1); + kernel.cmdUIDrawTexture( + ((WgpuTexture) texture).getTeraTexture(), + new Rectanglef(rightTex, bottomTex, 1, 1), + new Rectanglef(right, bottom, 1, 1) + .scale(region.getSizeX(), region.getSizeY()) + .translate(region.minX, region.minY)); + } + } + } } @Override From 52c27505e2c3c933f8354fd87a65d3a795481661 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 19 Jul 2023 20:49:46 -0700 Subject: [PATCH 08/13] feat: fix border Signed-off-by: Michael Pollind --- .../nui/internal/WgpuCanvasRenderer.java | 20 +++---------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/engine/src/main/java/org/terasology/engine/rendering/nui/internal/WgpuCanvasRenderer.java b/engine/src/main/java/org/terasology/engine/rendering/nui/internal/WgpuCanvasRenderer.java index 50d0d37b2f1..54f8ba3e079 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/nui/internal/WgpuCanvasRenderer.java +++ b/engine/src/main/java/org/terasology/engine/rendering/nui/internal/WgpuCanvasRenderer.java @@ -164,11 +164,7 @@ public void drawTextureBordered(UITextureRegion texture, Rectanglei absoluteRegi kernel.cmdUIDrawTexture( ((WgpuTexture) texture).getTeraTexture(), new Rectanglef(texCoordLeft, texCoordTop, texCoordRight, texCoordBottom), - new Rectanglef( vertLeft, vertTop, vertRight, vertBottom) - .scale(region.getSizeX(), region.getSizeY()) - .translate(region.minX, region.minY)); -// addRectPoly(builder, vertLeft, vertTop, vertRight, vertBottom, texCoordLeft, texCoordTop, -// texCoordRight, texCoordBottom); + new Rectanglef(vertLeft, vertTop, vertRight, vertBottom)); } } }; @@ -196,24 +192,19 @@ public void drawTextureBordered(UITextureRegion texture, Rectanglei absoluteRegi .translate(region.minX, region.minY)); } if (tile) { - cmdDrawTiles.accept(new Rectanglei(border.getLeft(), 0).setSize(centerHoriz, border.getTop()), new Rectanglef(left, 0, right, top), new Vector2i(textureSize.x - border.getTotalWidth(), border.getTop()), - new Rectanglef(leftTex, 0, rightTex, topTex) - .scale(region.getSizeX(), region.getSizeY()) - .translate(region.minX, region.minY)); + new Rectanglef(leftTex, 0, rightTex, topTex)); } else { -// addRectPoly(builder, left, 0, right, top, leftTex, 0, rightTex, topTex); kernel.cmdUIDrawTexture( ((WgpuTexture) texture).getTeraTexture(), new Rectanglef(leftTex, 0, rightTex, topTex), - new Rectanglef( left, 0, right, top).translate(region.minX, region.minY) + new Rectanglef(left, 0, right, top) .scale(region.getSizeX(), region.getSizeY()) .translate(region.minX, region.minY)); } if (border.getRight() != 0) { -// addRectPoly(builder, right, 0, 1, top, rightTex, 0, 1, topTex); kernel.cmdUIDrawTexture( ((WgpuTexture) texture).getTeraTexture(), new Rectanglef(rightTex, 0, 1, topTex), @@ -230,7 +221,6 @@ public void drawTextureBordered(UITextureRegion texture, Rectanglei absoluteRegi new Vector2i(border.getLeft(), textureSize.y - border.getTotalHeight()), new Rectanglef(0, topTex, leftTex, bottomTex)); } else { -// addRectPoly(builder, 0, top, left, bottom, 0, topTex, leftTex, bottomTex); kernel.cmdUIDrawTexture( ((WgpuTexture) texture).getTeraTexture(), new Rectanglef(0, topTex, leftTex, bottomTex), @@ -246,7 +236,6 @@ public void drawTextureBordered(UITextureRegion texture, Rectanglei absoluteRegi new Vector2i(textureSize.x - border.getTotalWidth(), textureSize.y - border.getTotalHeight()), new Rectanglef(leftTex, topTex, rightTex, bottomTex)); } else { -// addRectPoly(builder, left, top, right, bottom, leftTex, topTex, rightTex, bottomTex); kernel.cmdUIDrawTexture( ((WgpuTexture) texture).getTeraTexture(), new Rectanglef(leftTex, topTex, rightTex, bottomTex), @@ -274,7 +263,6 @@ public void drawTextureBordered(UITextureRegion texture, Rectanglei absoluteRegi if (border.getBottom() != 0) { if (border.getLeft() != 0) { -// addRectPoly(builder, 0, bottom, left, 1, 0, bottomTex, leftTex, 1); kernel.cmdUIDrawTexture( ((WgpuTexture) texture).getTeraTexture(), new Rectanglef(0, bottomTex, leftTex, 1), @@ -289,7 +277,6 @@ public void drawTextureBordered(UITextureRegion texture, Rectanglei absoluteRegi new Vector2i(textureSize.x - border.getTotalWidth(), border.getBottom()), new Rectanglef(leftTex, bottomTex, rightTex, 1)); } else { -// addRectPoly(builder, left, bottom, right, 1, leftTex, bottomTex, rightTex, 1); kernel.cmdUIDrawTexture( ((WgpuTexture) texture).getTeraTexture(), new Rectanglef(leftTex, bottomTex, rightTex, 1), @@ -298,7 +285,6 @@ public void drawTextureBordered(UITextureRegion texture, Rectanglei absoluteRegi .translate(region.minX, region.minY)); } if (border.getRight() != 0) { -// addRectPoly(builder, right, bottom, 1, 1, rightTex, bottomTex, 1, 1); kernel.cmdUIDrawTexture( ((WgpuTexture) texture).getTeraTexture(), new Rectanglef(rightTex, bottomTex, 1, 1), From 6b0fd90c67bb3c79d289dc573d04e49d22a0b782 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 19 Jul 2023 21:32:51 -0700 Subject: [PATCH 09/13] feat: add shadow to wgpu Signed-off-by: Michael Pollind --- .../nui/internal/WgpuCanvasRenderer.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/engine/src/main/java/org/terasology/engine/rendering/nui/internal/WgpuCanvasRenderer.java b/engine/src/main/java/org/terasology/engine/rendering/nui/internal/WgpuCanvasRenderer.java index 54f8ba3e079..aa078691f1a 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/nui/internal/WgpuCanvasRenderer.java +++ b/engine/src/main/java/org/terasology/engine/rendering/nui/internal/WgpuCanvasRenderer.java @@ -13,7 +13,6 @@ import org.terasology.engine.rendering.assets.font.FontCharacter; import org.terasology.engine.rendering.assets.material.Material; import org.terasology.engine.rendering.assets.mesh.Mesh; -import org.terasology.engine.rendering.assets.mesh.MeshBuilder; import org.terasology.engine.rendering.opengl.FrameBufferObject; import org.terasology.engine.rendering.opengl.WgpuTexture; import org.terasology.engine.rust.EngineKernel; @@ -23,8 +22,6 @@ import org.terasology.math.TeraMath; import org.terasology.nui.Border; import org.terasology.nui.Colorc; -import org.terasology.nui.FontColor; -import org.terasology.nui.FontUnderline; import org.terasology.nui.HorizontalAlign; import org.terasology.nui.ScaleMode; import org.terasology.nui.TextLineBuilder; @@ -32,12 +29,15 @@ import org.terasology.nui.VerticalAlign; import org.terasology.nui.asset.font.Font; import reactor.function.Consumer4; -import reactor.function.Consumer5; import java.util.List; public class WgpuCanvasRenderer implements TerasologyCanvasRenderer { private DisplayDevice displayDevice; + private static final float SHADOW_DEPTH = -2; + private static final int SHADOW_HORIZONTAL_OFFSET = 1; + private static final int SHADOW_VERTICAL_OFFSET = 1; + private static final int UNKNOWN = -1; public WgpuCanvasRenderer(Context context) { this.displayDevice = context.get(DisplayDevice.class); @@ -111,6 +111,14 @@ public void drawText(String text, Font font, HorizontalAlign hAlign, VerticalAli float texLeft = character.getX(); float texRight = texLeft + character.getTexWidth(); + if (shadowColor.a() != 0) { + kernel.cmdUIDrawTexture( + ((WgpuTexture) character.getPage()).getTeraTexture(), + new Rectanglef(texLeft, texTop, texRight, texBottom), + new Rectanglef(left + offset.x, top + offset.y, right + offset.x, bottom + offset.y) + .translate(SHADOW_HORIZONTAL_OFFSET, SHADOW_VERTICAL_OFFSET), + shadowColor.rgba()); + } kernel.cmdUIDrawTexture( ((WgpuTexture) character.getPage()).getTeraTexture(), new Rectanglef(texLeft, texTop, texRight, texBottom), From aa1f1634d2b18287f2307cc57fb6c12da68e8043 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 20 Jul 2023 07:36:36 -0700 Subject: [PATCH 10/13] feat: add crop Signed-off-by: Michael Pollind --- .../engine/rendering/nui/internal/WgpuCanvasRenderer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/engine/src/main/java/org/terasology/engine/rendering/nui/internal/WgpuCanvasRenderer.java b/engine/src/main/java/org/terasology/engine/rendering/nui/internal/WgpuCanvasRenderer.java index aa078691f1a..8a9d4d0b90a 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/nui/internal/WgpuCanvasRenderer.java +++ b/engine/src/main/java/org/terasology/engine/rendering/nui/internal/WgpuCanvasRenderer.java @@ -31,6 +31,7 @@ import reactor.function.Consumer4; import java.util.List; +import java.util.Optional; public class WgpuCanvasRenderer implements TerasologyCanvasRenderer { private DisplayDevice displayDevice; @@ -61,7 +62,7 @@ public Vector2i getTargetSize() { @Override public void crop(Rectanglei cropRegion) { EngineKernel kernel = EngineKernel.instance(); - + kernel.cmdUISetCrop(Optional.of(new Rectanglef(cropRegion.minX(), cropRegion.minY(), cropRegion.maxX(), cropRegion.maxY()))); } @Override From af5fa40f01b61fa16fc4d6edf0cc345d35ab2049 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sun, 23 Jul 2023 17:01:30 -0700 Subject: [PATCH 11/13] rework lwjgl code Signed-off-by: Michael Pollind --- .../engine/core/TerasologyEngine.java | 2 - .../core/subsystem/lwjgl/LwjglGraphics.java | 101 ++++++++++++++---- .../subsystem/lwjgl/LwjglGraphicsManager.java | 45 -------- .../nui/internal/WgpuCanvasRenderer.java | 37 +++---- .../engine/rendering/opengl/GLSLMaterial.java | 32 +++--- .../engine/rendering/opengl/WgpuTexture.java | 29 +++-- 6 files changed, 125 insertions(+), 121 deletions(-) diff --git a/engine/src/main/java/org/terasology/engine/core/TerasologyEngine.java b/engine/src/main/java/org/terasology/engine/core/TerasologyEngine.java index 2fd0a9f6670..6e48cb76912 100644 --- a/engine/src/main/java/org/terasology/engine/core/TerasologyEngine.java +++ b/engine/src/main/java/org/terasology/engine/core/TerasologyEngine.java @@ -163,7 +163,6 @@ public TerasologyEngine(TimeSubsystem timeSubsystem, Collection DirectionAndOriginPosRecorderList directionAndOriginPosRecorderList = new DirectionAndOriginPosRecorderList(); rootContext.put(DirectionAndOriginPosRecorderList.class, directionAndOriginPosRecorderList); - EngineKernel.initialize(); /* * We can't load the engine without core registry yet. * e.g. the statically created MaterialLoader needs the CoreRegistry to get the AssetManager. @@ -559,7 +558,6 @@ public void cleanup() { logger.error("Error shutting down {} subsystem", subsystem.getName(), e); } } - EngineKernel.disposeKernel(); } /** diff --git a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java index 598b6d698af..f2c333d3811 100644 --- a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java +++ b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java @@ -18,9 +18,31 @@ import org.terasology.engine.core.subsystem.DisplayDevice; import org.terasology.engine.rendering.ShaderManager; import org.terasology.engine.rendering.ShaderManagerLwjgl; +import org.terasology.engine.rendering.assets.animation.MeshAnimation; +import org.terasology.engine.rendering.assets.animation.MeshAnimationBundle; +import org.terasology.engine.rendering.assets.animation.MeshAnimationImpl; +import org.terasology.engine.rendering.assets.atlas.Atlas; +import org.terasology.engine.rendering.assets.font.Font; +import org.terasology.engine.rendering.assets.font.FontImpl; +import org.terasology.engine.rendering.assets.material.Material; +import org.terasology.engine.rendering.assets.mesh.Mesh; +import org.terasology.engine.rendering.assets.shader.Shader; +import org.terasology.engine.rendering.assets.skeletalmesh.SkeletalMesh; +import org.terasology.engine.rendering.assets.texture.PNGTextureFormat; +import org.terasology.engine.rendering.assets.texture.Texture; +import org.terasology.engine.rendering.assets.texture.TextureData; +import org.terasology.engine.rendering.assets.texture.subtexture.Subtexture; import org.terasology.engine.rendering.nui.internal.WgpuCanvasRenderer; +import org.terasology.engine.rendering.opengl.GLSLMaterial; +import org.terasology.engine.rendering.opengl.GLSLShader; +import org.terasology.engine.rendering.opengl.OpenGLMesh; +import org.terasology.engine.rendering.opengl.OpenGLSkeletalMesh; +import org.terasology.engine.rendering.opengl.WgpuTexture; import org.terasology.engine.rust.EngineKernel; import org.terasology.engine.utilities.OS; +import org.terasology.gestalt.assets.AssetType; +import org.terasology.gestalt.assets.ResourceUrn; +import org.terasology.gestalt.assets.module.ModuleAssetScanner; import org.terasology.gestalt.assets.module.ModuleAwareAssetTypeManager; import org.terasology.nui.canvas.CanvasRenderer; @@ -33,13 +55,13 @@ public class LwjglGraphics extends BaseLwjglSubsystem { // we don't use context so we need to public static long primaryWindow = 0; + private EngineKernel kernel = null; private Context context; private RenderingConfig config; private GameEngine engine; private LwjglDisplayDevice lwjglDisplay; -// private EngineKernel kernel; private LwjglGraphicsManager graphics = new LwjglGraphicsManager(); @@ -61,13 +83,56 @@ public void initialise(GameEngine gameEngine, Context rootContext) { @Override public void registerCoreAssetTypes(ModuleAwareAssetTypeManager assetTypeManager) { - graphics.registerCoreAssetTypes(assetTypeManager); + + AssetType texture = assetTypeManager.createAssetType(Texture.class, + (ResourceUrn urn, AssetType assetType, TextureData data) -> { + WgpuTexture.TextureResources resources = new WgpuTexture.TextureResources( + data, + this.kernel.resource.createTexture(WgpuTexture.createDesc(data), data.getBuffers()[0]) + ); + + return new WgpuTexture(this.kernel, urn, assetType, resources); + }, "textures", "fonts"); + assetTypeManager.getAssetFileDataProducer(texture).addAssetFormat( + new PNGTextureFormat(Texture.FilterMode.NEAREST, path -> { + if (path.getPath().get(0).equals(ModuleAssetScanner.OVERRIDE_FOLDER)) { + return path.getPath().get(2).equals("textures"); + } else { + return path.getPath().get(1).equals("textures"); + } + })); + assetTypeManager.getAssetFileDataProducer(texture).addAssetFormat( + new PNGTextureFormat(Texture.FilterMode.LINEAR, path -> { + if (path.getPath().get(0).equals(ModuleAssetScanner.OVERRIDE_FOLDER)) { + return path.getPath().get(2).equals("fonts"); + } else { + return path.getPath().get(1).equals("fonts"); + } + })); + assetTypeManager.createAssetType(Font.class, + FontImpl::new, "fonts"); + + assetTypeManager.createAssetType(Shader.class, (urn, assetType, data) -> GLSLShader.create(urn, assetType, data, graphics), "shaders"); + assetTypeManager.createAssetType(Material.class, (urn, assetType, data) -> + GLSLMaterial.create(urn, graphics, assetType, data), + "materials"); + assetTypeManager.createAssetType(Mesh.class, (urn, assetType, data) -> OpenGLMesh.create(urn, assetType, data, graphics), + "mesh"); + assetTypeManager.createAssetType(SkeletalMesh.class, + (urn, assetType, data) -> + OpenGLSkeletalMesh.create(urn, assetType, data, graphics), + "skeletalMesh"); + assetTypeManager.createAssetType(MeshAnimation.class, MeshAnimationImpl::new, + "animations", "skeletalMesh"); + assetTypeManager.createAssetType(Atlas.class, Atlas::new, "atlas"); + assetTypeManager.createAssetType(MeshAnimationBundle.class, MeshAnimationBundle::new, + "skeletalMesh", "animations"); + assetTypeManager.createAssetType(Subtexture.class, Subtexture::new); } @Override public void postInitialise(Context rootContext) { graphics.registerRenderingSubsystem(context); -// this.kernel = context.get(EngineKernel.class); if (!GLFW.glfwInit()) { throw new RuntimeException("Failed to initialize GLFW"); @@ -87,28 +152,27 @@ public void postInitialise(Context rootContext) { long window = GLFW.glfwCreateWindow( config.getWindowWidth(), config.getWindowHeight(), "Terasology Alpha", 0, 0); + primaryWindow = window; - switch(GLFW.glfwGetPlatform()) { + EngineKernel.EngineKernelBuild builder = new EngineKernel.EngineKernelBuild(); + switch (GLFW.glfwGetPlatform()) { case GLFW.GLFW_PLATFORM_X11: - EngineKernel.instance().initializeWinX11Surface(GLFWNativeX11.glfwGetX11Display(), - GLFWNativeX11.glfwGetX11Window(window)); + builder.configureX11Window(GLFWNativeX11.glfwGetX11Window(window), GLFWNativeX11.glfwGetX11Display()); break; case GLFW.GLFW_PLATFORM_WIN32: - EngineKernel.instance().initializeWin32Surface( - GLFWNativeWin32.nglfwGetWin32Adapter(window), - GLFWNativeWin32.glfwGetWin32Window(window)); + builder.configureWin32Window(GLFWNativeWin32.glfwGetWin32Window(window), GLFWNativeWin32.nglfwGetWin32Adapter(window)); break; default: throw new RuntimeException("missing platform: " + GLFW.glfwGetPlatform()); } - + this.kernel = new EngineKernel(builder); + context.put(EngineKernel.class, this.kernel); + this.kernel.resizeSurface(lwjglDisplay.getWidth(), lwjglDisplay.getHeight()); if (window == 0) { throw new RuntimeException("Failed to create window"); } - primaryWindow = window; - EngineKernel.instance().resizeSurface(lwjglDisplay.getWidth(), lwjglDisplay.getHeight()); if (OS.get() != OS.MACOSX) { try { String root = "org/terasology/engine/icons/"; @@ -137,7 +201,7 @@ public void postInitialise(Context rootContext) { @Override public void invoke(long window, int width, int height) { lwjglDisplay.updateViewport(width, height); - EngineKernel.instance().resizeSurface(width, height); + kernel.resizeSurface(width, height); } }); @@ -151,10 +215,9 @@ public void postUpdate(GameState currentState, float delta) { boolean gameWindowIsMinimized = GLFW.glfwGetWindowAttrib(LwjglGraphics.primaryWindow, GLFW.GLFW_ICONIFIED) == GLFW.GLFW_TRUE; if (!gameWindowIsMinimized) { - EngineKernel kernel = EngineKernel.instance(); - kernel.cmdPrepare(); + this.kernel.cmdPrepare(); currentState.render(); - kernel.cmdDispatch(); + this.kernel.cmdDispatch(); } lwjglDisplay.update(); @@ -169,7 +232,6 @@ public void postUpdate(GameState currentState, float delta) { @Override public void preShutdown() { -// long window = GLFW.glfwGetCurrentContext(); if (primaryWindow != MemoryUtil.NULL) { boolean isVisible = GLFW.glfwGetWindowAttrib(primaryWindow, GLFW.GLFW_VISIBLE) == GLFW.GLFW_TRUE; boolean isFullScreen = lwjglDisplay.isFullscreen(); @@ -195,9 +257,4 @@ public void preShutdown() { public void shutdown() { GLFW.glfwTerminate(); } - - private void initWindow() { - - } - } diff --git a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphicsManager.java b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphicsManager.java index 5a6bed45dc3..b43cab70acf 100644 --- a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphicsManager.java +++ b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphicsManager.java @@ -58,56 +58,11 @@ public void setThreadMode(ThreadMode threadMode) { this.threadMode = threadMode; } - public void registerCoreAssetTypes(ModuleAwareAssetTypeManager assetTypeManager) { - // cast lambdas explicitly to avoid inconsistent compiler behavior wrt. type inference - assetTypeManager.createAssetType(Font.class, - FontImpl::new, "fonts"); - //AssetType texture = assetTypeManager.createAssetType(Texture.class, - // (urn, assetType, data) -> (OpenGLTexture.create(urn, assetType, data, this)), "textures", "fonts"); - AssetType texture = assetTypeManager.createAssetType(Texture.class, - WgpuTexture::create, "textures", "fonts"); - - assetTypeManager.getAssetFileDataProducer(texture).addAssetFormat( - new PNGTextureFormat(Texture.FilterMode.NEAREST, path -> { - if (path.getPath().get(0).equals(ModuleAssetScanner.OVERRIDE_FOLDER)) { - return path.getPath().get(2).equals("textures"); - } else { - return path.getPath().get(1).equals("textures"); - } - })); - assetTypeManager.getAssetFileDataProducer(texture).addAssetFormat( - new PNGTextureFormat(Texture.FilterMode.LINEAR, path -> { - if (path.getPath().get(0).equals(ModuleAssetScanner.OVERRIDE_FOLDER)) { - return path.getPath().get(2).equals("fonts"); - } else { - return path.getPath().get(1).equals("fonts"); - } - })); - assetTypeManager.createAssetType(Shader.class, (urn, assetType, data) -> GLSLShader.create(urn, assetType, data, this), "shaders"); - assetTypeManager.createAssetType(Material.class, (urn, assetType, data) -> - GLSLMaterial.create(urn, this, assetType, data), - "materials"); - assetTypeManager.createAssetType(Mesh.class, (urn, assetType, data) -> OpenGLMesh.create(urn, assetType, data, this), - "mesh"); - assetTypeManager.createAssetType(SkeletalMesh.class, - (urn, assetType, data) -> - OpenGLSkeletalMesh.create(urn, assetType, data, this), - "skeletalMesh"); - assetTypeManager.createAssetType(MeshAnimation.class, MeshAnimationImpl::new, - "animations", "skeletalMesh"); - assetTypeManager.createAssetType(Atlas.class, Atlas::new, "atlas"); - assetTypeManager.createAssetType(MeshAnimationBundle.class, MeshAnimationBundle::new, - "skeletalMesh", "animations"); - assetTypeManager.createAssetType(Subtexture.class, Subtexture::new); - } - public void registerRenderingSubsystem(Context context) { context.put(RenderingSubsystemFactory.class, new LwjglRenderingSubsystemFactory()); } public void processActions() { -// LwjglGraphicsUtil.updateDisplayDeviceInfo(displayDeviceInfo); - if (!displayThreadActions.isEmpty()) { List actions = Lists.newArrayListWithExpectedSize(displayThreadActions.size()); displayThreadActions.drainTo(actions); diff --git a/engine/src/main/java/org/terasology/engine/rendering/nui/internal/WgpuCanvasRenderer.java b/engine/src/main/java/org/terasology/engine/rendering/nui/internal/WgpuCanvasRenderer.java index 8a9d4d0b90a..417a445591a 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/nui/internal/WgpuCanvasRenderer.java +++ b/engine/src/main/java/org/terasology/engine/rendering/nui/internal/WgpuCanvasRenderer.java @@ -34,13 +34,15 @@ import java.util.Optional; public class WgpuCanvasRenderer implements TerasologyCanvasRenderer { - private DisplayDevice displayDevice; private static final float SHADOW_DEPTH = -2; private static final int SHADOW_HORIZONTAL_OFFSET = 1; private static final int SHADOW_VERTICAL_OFFSET = 1; private static final int UNKNOWN = -1; + private DisplayDevice displayDevice; + private final EngineKernel kernel; public WgpuCanvasRenderer(Context context) { + this.kernel = context.get(EngineKernel.class); this.displayDevice = context.get(DisplayDevice.class); } @@ -61,8 +63,7 @@ public Vector2i getTargetSize() { @Override public void crop(Rectanglei cropRegion) { - EngineKernel kernel = EngineKernel.instance(); - kernel.cmdUISetCrop(Optional.of(new Rectanglef(cropRegion.minX(), cropRegion.minY(), cropRegion.maxX(), cropRegion.maxY()))); + kernel.ui.cmdUISetCrop(Optional.of(new Rectanglef(cropRegion.minX(), cropRegion.minY(), cropRegion.maxX(), cropRegion.maxY()))); } @Override @@ -72,11 +73,10 @@ public void drawLine(int sx, int sy, int ex, int ey, Colorc color) { @Override public void drawTexture(UITextureRegion texture, Colorc color, ScaleMode mode, Rectanglei absoluteRegion, float ux, float uy, float uw, float uh, float alpha) { - EngineKernel kernel = EngineKernel.instance(); if (texture instanceof WgpuTexture) { Vector2fc size = ((WgpuTexture) texture).getTeraTexture().getSize(); - kernel.cmdUIDrawTexture( + kernel.ui.cmdUIDrawTexture( ((WgpuTexture) texture).getTeraTexture(), new Rectanglef(ux, uy , ux + uw, uy + uh), new Rectanglef(absoluteRegion.minX(), absoluteRegion.minY(), absoluteRegion.maxX(), absoluteRegion.maxY())); @@ -87,8 +87,6 @@ public void drawTexture(UITextureRegion texture, Colorc color, ScaleMode mode, R @Override public void drawText(String text, Font font, HorizontalAlign hAlign, VerticalAlign vAlign, Rectanglei absoluteRegion, Colorc color, Colorc shadowColor, float alpha, boolean underlined) { - EngineKernel kernel = EngineKernel.instance(); - List lines = TextLineBuilder.getLines(font, text, absoluteRegion.getSizeX()); Vector2i offset = new Vector2i(absoluteRegion.minX, absoluteRegion.minY); offset.y += vAlign.getOffset(lines.size() * font.getLineHeight(), absoluteRegion.lengthY()); @@ -113,14 +111,14 @@ public void drawText(String text, Font font, HorizontalAlign hAlign, VerticalAli float texRight = texLeft + character.getTexWidth(); if (shadowColor.a() != 0) { - kernel.cmdUIDrawTexture( + kernel.ui.cmdUIDrawTexture( ((WgpuTexture) character.getPage()).getTeraTexture(), new Rectanglef(texLeft, texTop, texRight, texBottom), new Rectanglef(left + offset.x, top + offset.y, right + offset.x, bottom + offset.y) .translate(SHADOW_HORIZONTAL_OFFSET, SHADOW_VERTICAL_OFFSET), shadowColor.rgba()); } - kernel.cmdUIDrawTexture( + kernel.ui.cmdUIDrawTexture( ((WgpuTexture) character.getPage()).getTeraTexture(), new Rectanglef(texLeft, texTop, texRight, texBottom), new Rectanglef(left + offset.x, top + offset.y, right + offset.x, bottom + offset.y)); @@ -133,7 +131,6 @@ public void drawText(String text, Font font, HorizontalAlign hAlign, VerticalAli @Override public void drawTextureBordered(UITextureRegion texture, Rectanglei absoluteRegion, Border border, boolean tile, float ux, float uy, float uw, float uh, float alpha) { - EngineKernel kernel = EngineKernel.instance(); Vector2i textureSize = new Vector2i(TeraMath.ceilToInt(texture.getWidth() * uw), TeraMath.ceilToInt(texture.getHeight() * uh)); Rectanglei region = new Rectanglei(absoluteRegion); @@ -170,7 +167,7 @@ public void drawTextureBordered(UITextureRegion texture, Rectanglei absoluteRegi drawRegion.getSizeX()) - left) / tileW; float texCoordBottom = subTextureRegion.minY + subTextureRegion.getSizeY() * (Math.min(top + tileH, drawRegion.getSizeY()) - top) / tileH; - kernel.cmdUIDrawTexture( + kernel.ui.cmdUIDrawTexture( ((WgpuTexture) texture).getTeraTexture(), new Rectanglef(texCoordLeft, texCoordTop, texCoordRight, texCoordBottom), new Rectanglef(vertLeft, vertTop, vertRight, vertBottom)); @@ -193,7 +190,7 @@ public void drawTextureBordered(UITextureRegion texture, Rectanglei absoluteRegi if (border.getTop() != 0) { if (border.getLeft() != 0) { - kernel.cmdUIDrawTexture( + kernel.ui.cmdUIDrawTexture( ((WgpuTexture) texture).getTeraTexture(), new Rectanglef(0, 0, leftTex, topTex), new Rectanglef(0, 0, left, top) @@ -206,7 +203,7 @@ public void drawTextureBordered(UITextureRegion texture, Rectanglei absoluteRegi new Vector2i(textureSize.x - border.getTotalWidth(), border.getTop()), new Rectanglef(leftTex, 0, rightTex, topTex)); } else { - kernel.cmdUIDrawTexture( + kernel.ui.cmdUIDrawTexture( ((WgpuTexture) texture).getTeraTexture(), new Rectanglef(leftTex, 0, rightTex, topTex), new Rectanglef(left, 0, right, top) @@ -214,7 +211,7 @@ public void drawTextureBordered(UITextureRegion texture, Rectanglei absoluteRegi .translate(region.minX, region.minY)); } if (border.getRight() != 0) { - kernel.cmdUIDrawTexture( + kernel.ui.cmdUIDrawTexture( ((WgpuTexture) texture).getTeraTexture(), new Rectanglef(rightTex, 0, 1, topTex), new Rectanglef(right, 0, 1, top) @@ -230,7 +227,7 @@ public void drawTextureBordered(UITextureRegion texture, Rectanglei absoluteRegi new Vector2i(border.getLeft(), textureSize.y - border.getTotalHeight()), new Rectanglef(0, topTex, leftTex, bottomTex)); } else { - kernel.cmdUIDrawTexture( + kernel.ui.cmdUIDrawTexture( ((WgpuTexture) texture).getTeraTexture(), new Rectanglef(0, topTex, leftTex, bottomTex), new Rectanglef( 0, top, left, bottom) @@ -245,7 +242,7 @@ public void drawTextureBordered(UITextureRegion texture, Rectanglei absoluteRegi new Vector2i(textureSize.x - border.getTotalWidth(), textureSize.y - border.getTotalHeight()), new Rectanglef(leftTex, topTex, rightTex, bottomTex)); } else { - kernel.cmdUIDrawTexture( + kernel.ui.cmdUIDrawTexture( ((WgpuTexture) texture).getTeraTexture(), new Rectanglef(leftTex, topTex, rightTex, bottomTex), new Rectanglef(left, top, right, bottom) @@ -261,7 +258,7 @@ public void drawTextureBordered(UITextureRegion texture, Rectanglei absoluteRegi new Vector2i(border.getRight(), textureSize.y - border.getTotalHeight()), new Rectanglef(rightTex, topTex, 1, bottomTex)); } else { - kernel.cmdUIDrawTexture( + kernel.ui.cmdUIDrawTexture( ((WgpuTexture) texture).getTeraTexture(), new Rectanglef(rightTex, topTex, 1, bottomTex), new Rectanglef(right, top, 1, bottom) @@ -272,7 +269,7 @@ public void drawTextureBordered(UITextureRegion texture, Rectanglei absoluteRegi if (border.getBottom() != 0) { if (border.getLeft() != 0) { - kernel.cmdUIDrawTexture( + kernel.ui.cmdUIDrawTexture( ((WgpuTexture) texture).getTeraTexture(), new Rectanglef(0, bottomTex, leftTex, 1), new Rectanglef(0, bottom, left, 1) @@ -286,7 +283,7 @@ public void drawTextureBordered(UITextureRegion texture, Rectanglei absoluteRegi new Vector2i(textureSize.x - border.getTotalWidth(), border.getBottom()), new Rectanglef(leftTex, bottomTex, rightTex, 1)); } else { - kernel.cmdUIDrawTexture( + kernel.ui.cmdUIDrawTexture( ((WgpuTexture) texture).getTeraTexture(), new Rectanglef(leftTex, bottomTex, rightTex, 1), new Rectanglef(left, bottom, right, 1) @@ -294,7 +291,7 @@ public void drawTextureBordered(UITextureRegion texture, Rectanglei absoluteRegi .translate(region.minX, region.minY)); } if (border.getRight() != 0) { - kernel.cmdUIDrawTexture( + kernel.ui.cmdUIDrawTexture( ((WgpuTexture) texture).getTeraTexture(), new Rectanglef(rightTex, bottomTex, 1, 1), new Rectanglef(right, bottom, 1, 1) diff --git a/engine/src/main/java/org/terasology/engine/rendering/opengl/GLSLMaterial.java b/engine/src/main/java/org/terasology/engine/rendering/opengl/GLSLMaterial.java index f42cdddc9c3..6fb3c022169 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/opengl/GLSLMaterial.java +++ b/engine/src/main/java/org/terasology/engine/rendering/opengl/GLSLMaterial.java @@ -648,22 +648,22 @@ private static class DisposalAction implements DisposableResource { @Override public void close() { - try { - GameThread.synch(() -> { - logger.debug("Disposing material {}.", urn); - final TIntIntMap deletedPrograms = new TIntIntHashMap(shaderPrograms); - graphicsProcessing.asynchToDisplayThread(() -> { - TIntIntIterator it = deletedPrograms.iterator(); - while (it.hasNext()) { - it.advance(); - GL20.glDeleteProgram(it.value()); - } - }); - shaderPrograms.clear(); - }); - } catch (InterruptedException e) { - logger.error("Failed to dispose {}", urn, e); - } +// try { +// GameThread.synch(() -> { +// logger.debug("Disposing material {}.", urn); +// final TIntIntMap deletedPrograms = new TIntIntHashMap(shaderPrograms); +// graphicsProcessing.asynchToDisplayThread(() -> { +// TIntIntIterator it = deletedPrograms.iterator(); +// while (it.hasNext()) { +// it.advance(); +// GL20.glDeleteProgram(it.value()); +// } +// }); +// shaderPrograms.clear(); +// }); +// } catch (InterruptedException e) { +// logger.error("Failed to dispose {}", urn, e); +// } } } } diff --git a/engine/src/main/java/org/terasology/engine/rendering/opengl/WgpuTexture.java b/engine/src/main/java/org/terasology/engine/rendering/opengl/WgpuTexture.java index 10b06571a1b..0e411602032 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/opengl/WgpuTexture.java +++ b/engine/src/main/java/org/terasology/engine/rendering/opengl/WgpuTexture.java @@ -7,6 +7,7 @@ import org.joml.Vector2i; import org.terasology.engine.rendering.assets.texture.Texture; import org.terasology.engine.rendering.assets.texture.TextureData; +import org.terasology.engine.rust.EngineKernel; import org.terasology.engine.rust.TeraTexture; import org.terasology.gestalt.assets.AssetType; import org.terasology.gestalt.assets.DisposableResource; @@ -18,31 +19,27 @@ public class WgpuTexture extends Texture { - private TextureResources resource; - - private static TeraTexture.TextureDesc createDesc(TextureData data) { + private final EngineKernel kernel; + public static TeraTexture.TextureDesc createDesc(TextureData data) { TeraTexture.TextureDesc desc = new TeraTexture.TextureDesc(); - desc.format = TeraTexture.ImageFormat.R8G8B8A8_UNORM; - desc.dim = TeraTexture.TextureDimension.DIM_2D; - desc.width = data.getWidth(); - desc.height = data.getHeight(); - desc.layers = 1; + desc.setFormat(TeraTexture.ImageFormat.R8G8B8A8_UNORM) + .setDim(TeraTexture.TextureDimension.DIM_2D) + .setWidth(data.getWidth()) + .setHeight(data.getHeight()) + .setLayers(1); return desc; } - public WgpuTexture(ResourceUrn urn, AssetType assetType, TextureResources textureResources) { + public WgpuTexture(EngineKernel kernel, ResourceUrn urn, AssetType assetType, TextureResources textureResources) { super(urn, assetType); + this.kernel = kernel; this.resource = textureResources; } - public static WgpuTexture create(ResourceUrn urn, AssetType assetType, TextureData data) { - return new WgpuTexture(urn, assetType, new TextureResources(data, TeraTexture.createFromBuffer(createDesc(data), data.getBuffers()[0]))); - } - @Override protected void doReload(TextureData data) { - this.resource = new TextureResources(data, TeraTexture.createFromBuffer(createDesc(data), data.getBuffers()[0])); + this.resource = new TextureResources(data, this.kernel.resource.createTexture(createDesc(data), data.getBuffers()[0])); } @Override @@ -119,12 +116,12 @@ public TeraTexture getTeraTexture() { return this.resource.texture; } - private static class TextureResources implements DisposableResource { + public static class TextureResources implements DisposableResource { private final TeraTexture texture; private final List disposalSubscribers = Lists.newArrayList(); private final TextureData data; - TextureResources(TextureData data, TeraTexture texture) { + public TextureResources(TextureData data, TeraTexture texture) { this.data = data; this.texture = texture; } From e76799e91a1e9abafeb91b153693c64ddc3de4c9 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sun, 23 Jul 2023 21:56:08 -0700 Subject: [PATCH 12/13] feat: starteded working on deferred pipeline Signed-off-by: Michael Pollind --- .../modes/loadProcesses/InitialiseWorld.java | 4 +- .../subsystem/lwjgl/LwjglDisplayDevice.java | 2 +- .../subsystem/lwjgl/LwjglGraphicsManager.java | 30 -- .../engine/rendering/dag/ModuleRendering.java | 4 +- .../engine/rendering/opengl/GLSLMaterial.java | 123 +++---- .../engine/rendering/opengl/GLSLShader.java | 16 - .../rendering/opengl/OpenGLTexture.java | 262 ------------- .../rendering/primitives/ChunkMesh.java | 8 + .../primitives/ChunkTessellator.java | 6 +- .../rendering/world/DeferredRenderer.java | 347 ++++++++++++++++++ .../rendering/world/RenderableWorldImpl.java | 1 - .../rendering/world/WorldRendererImpl.java | 3 +- 12 files changed, 419 insertions(+), 387 deletions(-) delete mode 100644 engine/src/main/java/org/terasology/engine/rendering/opengl/OpenGLTexture.java create mode 100644 engine/src/main/java/org/terasology/engine/rendering/world/DeferredRenderer.java diff --git a/engine/src/main/java/org/terasology/engine/core/modes/loadProcesses/InitialiseWorld.java b/engine/src/main/java/org/terasology/engine/core/modes/loadProcesses/InitialiseWorld.java index ca3928ca025..c1b637c598f 100644 --- a/engine/src/main/java/org/terasology/engine/core/modes/loadProcesses/InitialiseWorld.java +++ b/engine/src/main/java/org/terasology/engine/core/modes/loadProcesses/InitialiseWorld.java @@ -31,6 +31,7 @@ import org.terasology.engine.rendering.backdrop.BackdropProvider; import org.terasology.engine.rendering.backdrop.Skysphere; import org.terasology.engine.rendering.cameras.Camera; +import org.terasology.engine.rendering.world.DeferredRenderer; import org.terasology.engine.rendering.world.WorldRenderer; import org.terasology.engine.utilities.random.FastRandom; import org.terasology.engine.world.BlockEntityRegistry; @@ -159,8 +160,7 @@ public boolean step() { BackdropProvider backdropProvider = skysphere; context.put(BackdropProvider.class, backdropProvider); - RenderingSubsystemFactory engineSubsystemFactory = context.get(RenderingSubsystemFactory.class); - WorldRenderer worldRenderer = engineSubsystemFactory.createWorldRenderer(context); + WorldRenderer worldRenderer = new DeferredRenderer(context); context.put(WorldRenderer.class, worldRenderer); // TODO: These shouldn't be done here, nor so strongly tied to the world renderer diff --git a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglDisplayDevice.java b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglDisplayDevice.java index 8b95d3a146e..73134f69486 100644 --- a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglDisplayDevice.java +++ b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglDisplayDevice.java @@ -178,7 +178,7 @@ public boolean isHeadless() { @Override public void prepareToRender() { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } @Override diff --git a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphicsManager.java b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphicsManager.java index b43cab70acf..f8aab8b7cf5 100644 --- a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphicsManager.java +++ b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphicsManager.java @@ -4,48 +4,18 @@ import com.google.common.collect.Lists; import com.google.common.collect.Queues; -import org.lwjgl.opengl.GL11; -import org.lwjgl.opengl.GL12; import org.terasology.engine.context.Context; import org.terasology.engine.core.GameThread; import org.terasology.engine.core.subsystem.DisplayDeviceInfo; import org.terasology.engine.core.subsystem.RenderingSubsystemFactory; -import org.terasology.engine.rendering.assets.animation.MeshAnimation; -import org.terasology.engine.rendering.assets.animation.MeshAnimationBundle; -import org.terasology.engine.rendering.assets.animation.MeshAnimationImpl; -import org.terasology.engine.rendering.assets.atlas.Atlas; -import org.terasology.engine.rendering.assets.font.Font; -import org.terasology.engine.rendering.assets.font.FontImpl; -import org.terasology.engine.rendering.assets.material.Material; -import org.terasology.engine.rendering.assets.mesh.Mesh; -import org.terasology.engine.rendering.assets.shader.Shader; -import org.terasology.engine.rendering.assets.skeletalmesh.SkeletalMesh; -import org.terasology.engine.rendering.assets.texture.PNGTextureFormat; import org.terasology.engine.rendering.assets.texture.Texture; -import org.terasology.engine.rendering.assets.texture.TextureData; -import org.terasology.engine.rendering.assets.texture.subtexture.Subtexture; -import org.terasology.engine.rendering.opengl.GLSLMaterial; -import org.terasology.engine.rendering.opengl.GLSLShader; -import org.terasology.engine.rendering.opengl.OpenGLMesh; -import org.terasology.engine.rendering.opengl.OpenGLSkeletalMesh; -import org.terasology.engine.rendering.opengl.OpenGLTexture; -import org.terasology.engine.rendering.opengl.WgpuTexture; -import org.terasology.gestalt.assets.AssetType; -import org.terasology.gestalt.assets.module.ModuleAssetScanner; -import org.terasology.gestalt.assets.module.ModuleAwareAssetTypeManager; import java.nio.ByteBuffer; import java.util.List; import java.util.concurrent.BlockingDeque; import java.util.function.Consumer; -import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; -import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_S; -import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_T; -import static org.lwjgl.opengl.GL11.glBindTexture; import static org.lwjgl.opengl.GL11.glDeleteTextures; -import static org.lwjgl.opengl.GL11.glGenTextures; -import static org.lwjgl.opengl.GL11.glTexParameterf; public class LwjglGraphicsManager implements LwjglGraphicsProcessing { diff --git a/engine/src/main/java/org/terasology/engine/rendering/dag/ModuleRendering.java b/engine/src/main/java/org/terasology/engine/rendering/dag/ModuleRendering.java index 2e0172e07fd..64c2baaf170 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/dag/ModuleRendering.java +++ b/engine/src/main/java/org/terasology/engine/rendering/dag/ModuleRendering.java @@ -26,7 +26,7 @@ public abstract class ModuleRendering { protected Context context; protected ModuleManager moduleManager; protected Name providingModule; - protected RenderGraph renderGraph; +// protected RenderGraph renderGraph; protected WorldRenderer worldRenderer; protected Boolean isEnabled = true; @@ -61,7 +61,7 @@ public void toggleEnabled() { } public void initialise() { - renderGraph = context.get(RenderGraph.class); +// renderGraph = context.get(RenderGraph.class); worldRenderer = context.get(WorldRenderer.class); } diff --git a/engine/src/main/java/org/terasology/engine/rendering/opengl/GLSLMaterial.java b/engine/src/main/java/org/terasology/engine/rendering/opengl/GLSLMaterial.java index 6fb3c022169..4c5645ffba2 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/opengl/GLSLMaterial.java +++ b/engine/src/main/java/org/terasology/engine/rendering/opengl/GLSLMaterial.java @@ -15,8 +15,6 @@ import org.joml.Matrix3fc; import org.joml.Matrix4fc; import org.lwjgl.BufferUtils; -import org.lwjgl.opengl.GL13; -import org.lwjgl.opengl.GL20; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.engine.core.GameThread; @@ -37,7 +35,6 @@ import java.util.Collections; import java.util.EnumSet; import java.util.Map; -import java.util.Set; public class GLSLMaterial extends BaseMaterial { @@ -50,7 +47,6 @@ public class GLSLMaterial extends BaseMaterial { private TIntObjectMap textureMap = new TIntObjectHashMap<>(); private GLSLShader shader; - private boolean activeFeaturesChanged; private TObjectIntMap uniformLocationMap = new TObjectIntHashMap<>(); private EnumSet activeFeatures = Sets.newEnumSet(Collections.emptyList(), ShaderProgramFeature.class); @@ -83,14 +79,14 @@ public static GLSLMaterial create(ResourceUrn urn, LwjglGraphicsProcessing graph @Override public void enable() { - if (shaderManager.getActiveMaterial() != this || activeFeaturesChanged) { - GL13.glActiveTexture(GL13.GL_TEXTURE0); - GL20.glUseProgram(getActiveShaderProgramId()); - - // Make sure the shader manager knows that this program is currently active - shaderManager.setActiveMaterial(this); - activeFeaturesChanged = false; - } +// if (shaderManager.getActiveMaterial() != this || activeFeaturesChanged) { +// GL13.glActiveTexture(GL13.GL_TEXTURE0); +// GL20.glUseProgram(getActiveShaderProgramId()); +// +// // Make sure the shader manager knows that this program is currently active +// shaderManager.setActiveMaterial(this); +// activeFeaturesChanged = false; +// } } @Override @@ -123,25 +119,25 @@ public boolean isRenderable() { @Override public void recompile() { - TIntIntIterator it = disposalAction.shaderPrograms.iterator(); - while (it.hasNext()) { - it.advance(); - GL20.glDeleteProgram(it.value()); - } - disposalAction.shaderPrograms.clear(); - uniformLocationMap.clear(); - bindMap.clear(); - - disposalAction.shaderPrograms.put(0, shader.linkShaderProgram(0)); - for (Set permutation : Sets.powerSet(shader.getAvailableFeatures())) { - int featureMask = ShaderProgramFeature.getBitset(permutation); - disposalAction.shaderPrograms.put(featureMask, shader.linkShaderProgram(featureMask)); - } - - //resolves #966 - //Some of the uniforms are not updated constantly between frames - //this function will rebind any uniforms that are not bound - rebindVariables(materialData); +// TIntIntIterator it = disposalAction.shaderPrograms.iterator(); +// while (it.hasNext()) { +// it.advance(); +// GL20.glDeleteProgram(it.value()); +// } +// disposalAction.shaderPrograms.clear(); +// uniformLocationMap.clear(); +// bindMap.clear(); +// +// disposalAction.shaderPrograms.put(0, shader.linkShaderProgram(0)); +// for (Set permutation : Sets.powerSet(shader.getAvailableFeatures())) { +// int featureMask = ShaderProgramFeature.getBitset(permutation); +// disposalAction.shaderPrograms.put(featureMask, shader.linkShaderProgram(featureMask)); +// } +// +// //resolves #966 +// //Some of the uniforms are not updated constantly between frames +// //this function will rebind any uniforms that are not bound +// rebindVariables(materialData); } @Override @@ -226,7 +222,7 @@ public void activateFeature(ShaderProgramFeature feature) { if (shader.getAvailableFeatures().contains(feature)) { activeFeatures.add(feature); activeFeaturesMask = ShaderProgramFeature.getBitset(activeFeatures); - activeFeaturesChanged = true; +// activeFeaturesChanged = true; } else { logger.error("Attempt to activate unsupported feature {} for material {} using shader {}", feature, getUrn(), shader.getUrn()); } @@ -236,7 +232,7 @@ public void activateFeature(ShaderProgramFeature feature) { public void deactivateFeature(ShaderProgramFeature feature) { if (activeFeatures.remove(feature)) { activeFeaturesMask = ShaderProgramFeature.getBitset(activeFeatures); - activeFeaturesChanged = true; +// activeFeaturesChanged = true; } } @@ -275,25 +271,25 @@ public void setFloat(String desc, float f, boolean currentOnly) { @Override public void setFloat1(String desc, FloatBuffer buffer, boolean currentOnly) { - if (isDisposed()) { - return; - } - if (currentOnly) { - enable(); - int id = getUniformLocation(getActiveShaderProgramId(), desc); - GL20.glUniform1fv(id, buffer); - } else { - TIntIntIterator it = disposalAction.shaderPrograms.iterator(); - while (it.hasNext()) { - it.advance(); - - GL20.glUseProgram(it.value()); - int id = getUniformLocation(it.value(), desc); - GL20.glUniform1fv(id, buffer); - } - - restoreStateAfterUniformsSet(); - } +// if (isDisposed()) { +// return; +// } +// if (currentOnly) { +// enable(); +// int id = getUniformLocation(getActiveShaderProgramId(), desc); +// GL20.glUniform1fv(id, buffer); +// } else { +// TIntIntIterator it = disposalAction.shaderPrograms.iterator(); +// while (it.hasNext()) { +// it.advance(); +// +// GL20.glUseProgram(it.value()); +// int id = getUniformLocation(it.value(), desc); +// GL20.glUniform1fv(id, buffer); +// } +// +// restoreStateAfterUniformsSet(); +// } } @Override @@ -581,25 +577,12 @@ private int getActiveShaderProgramId() { return disposalAction.shaderPrograms.get(activeFeaturesMask); } - private int getUniformLocation(int activeShaderProgramId, String desc) { - UniformId id = new UniformId(activeShaderProgramId, desc); - - if (uniformLocationMap.containsKey(id)) { - return uniformLocationMap.get(id); - } - - int loc = GL20.glGetUniformLocation(activeShaderProgramId, desc); - uniformLocationMap.put(id, loc); - - return loc; - } - private void restoreStateAfterUniformsSet() { - if (shaderManager.getActiveMaterial() == this) { - GL20.glUseProgram(getActiveShaderProgramId()); - } else { - enable(); - } +// if (shaderManager.getActiveMaterial() == this) { +// GL20.glUseProgram(getActiveShaderProgramId()); +// } else { +// enable(); +// } } private static final class UniformId { diff --git a/engine/src/main/java/org/terasology/engine/rendering/opengl/GLSLShader.java b/engine/src/main/java/org/terasology/engine/rendering/opengl/GLSLShader.java index 37b5c19ab9e..53911864a36 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/opengl/GLSLShader.java +++ b/engine/src/main/java/org/terasology/engine/rendering/opengl/GLSLShader.java @@ -116,25 +116,9 @@ Set getAvailableFeatures() { return availableFeatures; } - // made package-private after CheckStyle suggestion - int linkShaderProgram(int featureHash) { -// int shaderProgram = GL20.glCreateProgram(); -// -// GL20.glAttachShader(shaderProgram, disposalAction.fragmentPrograms.get(featureHash)); -// GL20.glAttachShader(shaderProgram, disposalAction.vertexPrograms.get(featureHash)); -// if (shaderProgramBase.getGeometryProgram() != null) { -// GL20.glAttachShader(shaderProgram, disposalAction.geometryPrograms.get(featureHash)); -// } -// GL20.glLinkProgram(shaderProgram); -// GL20.glValidateProgram(shaderProgram); - return 0; - } @Override public void recompile() { - graphicsProcessing.asynchToDisplayThread(() -> { -// registerAllShaderPermutations(); - }); } diff --git a/engine/src/main/java/org/terasology/engine/rendering/opengl/OpenGLTexture.java b/engine/src/main/java/org/terasology/engine/rendering/opengl/OpenGLTexture.java deleted file mode 100644 index 13a89423715..00000000000 --- a/engine/src/main/java/org/terasology/engine/rendering/opengl/OpenGLTexture.java +++ /dev/null @@ -1,262 +0,0 @@ -// Copyright 2021 The Terasology Foundation -// SPDX-License-Identifier: Apache-2.0 -package org.terasology.engine.rendering.opengl; - -import com.google.common.collect.Lists; -import org.joml.Vector2i; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.terasology.gestalt.assets.AssetType; -import org.terasology.gestalt.assets.DisposableResource; -import org.terasology.gestalt.assets.ResourceUrn; -import org.terasology.engine.core.subsystem.lwjgl.LwjglGraphicsManager; -import org.terasology.joml.geom.Rectanglef; -import org.terasology.joml.geom.Rectanglei; -import org.terasology.engine.rendering.assets.texture.Texture; -import org.terasology.engine.rendering.assets.texture.TextureData; - -import java.nio.ByteBuffer; -import java.util.List; - -public class OpenGLTexture extends Texture { - - private static final Logger logger = LoggerFactory.getLogger(OpenGLTexture.class); - - private final TextureResources resources; - - public OpenGLTexture(ResourceUrn urn, AssetType assetType, TextureData data, TextureResources textureResources) { - super(urn, assetType, textureResources); - this.resources = textureResources; - reload(data); - } - - public static OpenGLTexture create(ResourceUrn urn, AssetType assetType, TextureData data, LwjglGraphicsManager graphicsManager) { - return new OpenGLTexture(urn, assetType, data, new TextureResources(graphicsManager)); - } - - - public void setId(int id) { - resources.id = id; - } - - @Override - protected void doReload(TextureData data) { - switch (data.getType()) { - // TODO: reconsider how 3D textures handled (probably separate asset implementation with common interface? - case TEXTURE3D: - if (data.getWidth() % data.getHeight() != 0 || data.getWidth() / data.getHeight() != data.getHeight()) { - throw new RuntimeException("3D texture must be cubic (height^3) - width must thus be a multiple of height"); - } - int size = data.getHeight(); - - final int byteLength = 4 * 16 * 16 * 16; - final int strideX = 16 * 4; - final int strideY = 16 * 16 * 4; - final int strideZ = 4; - - ByteBuffer alignedBuffer = ByteBuffer.allocateDirect(byteLength); - for (int x = 0; x < size; x++) { - for (int y = 0; y < size; y++) { - for (int z = 0; z < size; z++) { - final int index = x * strideX + z * strideZ + strideY * y; - - alignedBuffer.put(data.getBuffers()[0].get(index)); - alignedBuffer.put(data.getBuffers()[0].get(index + 1)); - alignedBuffer.put(data.getBuffers()[0].get(index + 2)); - alignedBuffer.put(data.getBuffers()[0].get(index + 3)); - } - } - } - alignedBuffer.flip(); - - resources.loadedTextureInfo = new LoadedTextureInfo(size, size, size, data); - - if (resources.id == 0) { - resources.graphicsManager.createTexture3D(alignedBuffer, getWrapMode(), getFilterMode(), - size, (newId) -> { - synchronized (this) { - if (resources.id != 0) { - resources.graphicsManager.disposeTexture(resources.id); - } - if (isDisposed()) { - resources.graphicsManager.disposeTexture(newId); - } else { - resources.id = newId; - logger.debug("Bound texture '{}' - {}", getUrn(), resources.id); - } - } - }); - } else { - resources.graphicsManager.reloadTexture3D(resources.id, alignedBuffer, getWrapMode(), getFilterMode(), size); - } - break; - default: - int width = data.getWidth(); - int height = data.getHeight(); - resources.loadedTextureInfo = new LoadedTextureInfo(width, height, 1, data); - if (resources.id == 0) { - resources.graphicsManager.createTexture2D(data.getBuffers(), getWrapMode(), getFilterMode(), width, height, (newId) -> { - synchronized (this) { - if (resources.id != 0) { - resources.graphicsManager.disposeTexture(resources.id); - } - if (isDisposed()) { - resources.graphicsManager.disposeTexture(newId); - } else { - resources.id = newId; - logger.debug("Bound texture '{}' - {}", getUrn(), resources.id); - } - } - }); - } else { - resources.graphicsManager.reloadTexture2D(resources.id, data.getBuffers(), getWrapMode(), getFilterMode(), width, height); - } - break; - } - } - - @Override - public int getId() { - return resources.id; - } - - @Override - public int getDepth() { - if (resources.loadedTextureInfo != null) { - return resources.loadedTextureInfo.getDepth(); - } - return 0; - } - - @Override - public int getWidth() { - if (resources.loadedTextureInfo != null) { - return resources.loadedTextureInfo.getWidth(); - } - return 0; - } - - @Override - public int getHeight() { - if (resources.loadedTextureInfo != null) { - return resources.loadedTextureInfo.getHeight(); - } - return 0; - } - - @Override - public Vector2i size() { - return new Vector2i(getWidth(), getHeight()); - } - - @Override - public Texture.WrapMode getWrapMode() { - return resources.loadedTextureInfo.getWrapMode(); - } - - @Override - public FilterMode getFilterMode() { - return resources.loadedTextureInfo.getFilterMode(); - } - - @Override - public TextureData getData() { - return new TextureData(resources.loadedTextureInfo.getTextureData()); - } - - @Override - public Texture getTexture() { - return this; - } - - @Override - public Rectanglef getRegion() { - return new Rectanglef(FULL_TEXTURE_REGION); // object is not guarded - } - - @Override - public Rectanglei getPixelRegion() { - return new Rectanglei(0, 0, getWidth(), getHeight()); - } - - @Override - public synchronized void subscribeToDisposal(DisposableResource subscriber) { - resources.disposalSubscribers.add(subscriber); - } - - @Override - public synchronized void unsubscribeToDisposal(DisposableResource subscriber) { - resources.disposalSubscribers.remove(subscriber); - } - - @Override - public boolean isLoaded() { - return resources.id != 0; - } - - private static class LoadedTextureInfo { - private final int width; - private final int height; - private final int depth; - private final Texture.WrapMode wrapMode; - private final Texture.FilterMode filterMode; - private final TextureData textureData; - - LoadedTextureInfo(int width, int height, int depth, TextureData data) { - this.width = width; - this.height = height; - this.depth = depth; - this.wrapMode = data.getWrapMode(); - this.filterMode = data.getFilterMode(); - this.textureData = data; - } - - public int getWidth() { - return width; - } - - public int getHeight() { - return height; - } - - public int getDepth() { - return depth; - } - - public Texture.WrapMode getWrapMode() { - return wrapMode; - } - - public Texture.FilterMode getFilterMode() { - return filterMode; - } - - public TextureData getTextureData() { - return textureData; - } - } - - private static class TextureResources implements DisposableResource { - - private final LwjglGraphicsManager graphicsManager; - private volatile int id; - private volatile LoadedTextureInfo loadedTextureInfo; - - private final List disposalSubscribers = Lists.newArrayList(); - - TextureResources(LwjglGraphicsManager graphicsManager) { - this.graphicsManager = graphicsManager; - } - - - @Override - public void close() { - if (loadedTextureInfo != null) { - disposalSubscribers.forEach(DisposableResource::close); - graphicsManager.disposeTexture(id); - loadedTextureInfo = null; - id = 0; - } - } - } -} diff --git a/engine/src/main/java/org/terasology/engine/rendering/primitives/ChunkMesh.java b/engine/src/main/java/org/terasology/engine/rendering/primitives/ChunkMesh.java index c4a36c154af..0c05bcbd3a0 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/primitives/ChunkMesh.java +++ b/engine/src/main/java/org/terasology/engine/rendering/primitives/ChunkMesh.java @@ -97,6 +97,14 @@ class VertexElements { public static final int COLOR_INDEX = 8; // vec4 public final VertexResource buffer; + +// public final VertexResource positionBuffer; +// public final VertexResource NormalBuffer; +// public final VertexResource uvBuffer; +// public final VertexResource ColroBuffer; +// public final VertexResource AttributeBuffer; + + public final IndexResource indices = new IndexResource(); public final VertexAttributeBinding position; diff --git a/engine/src/main/java/org/terasology/engine/rendering/primitives/ChunkTessellator.java b/engine/src/main/java/org/terasology/engine/rendering/primitives/ChunkTessellator.java index c6ca1835c58..a64404b8db2 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/primitives/ChunkTessellator.java +++ b/engine/src/main/java/org/terasology/engine/rendering/primitives/ChunkTessellator.java @@ -5,6 +5,7 @@ import com.google.common.base.Stopwatch; import org.joml.Vector3f; import org.terasology.engine.monitoring.PerformanceMonitor; +import org.terasology.engine.rust.EngineKernel; import org.terasology.engine.world.ChunkView; import org.terasology.engine.world.block.Block; import org.terasology.engine.world.chunks.Chunks; @@ -18,9 +19,10 @@ public final class ChunkTessellator { private static int statVertexArrayUpdateCount; + private final EngineKernel kernel; - public ChunkTessellator() { - + public ChunkTessellator(EngineKernel kernel) { + this.kernel = kernel; } public ChunkMesh generateMesh(ChunkView chunkView) { diff --git a/engine/src/main/java/org/terasology/engine/rendering/world/DeferredRenderer.java b/engine/src/main/java/org/terasology/engine/rendering/world/DeferredRenderer.java new file mode 100644 index 00000000000..9663aa86a52 --- /dev/null +++ b/engine/src/main/java/org/terasology/engine/rendering/world/DeferredRenderer.java @@ -0,0 +1,347 @@ +// Copyright 2023 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.engine.rendering.world; + +import org.joml.Vector3f; +import org.joml.Vector3ic; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.terasology.engine.config.Config; +import org.terasology.engine.config.RenderingConfig; +import org.terasology.engine.context.Context; +import org.terasology.engine.core.GameEngine; +import org.terasology.engine.core.modes.StateMainMenu; +import org.terasology.engine.core.module.ModuleManager; +import org.terasology.engine.core.module.rendering.RenderingModuleRegistry; +import org.terasology.engine.core.subsystem.DisplayDevice; +import org.terasology.engine.logic.console.Console; +import org.terasology.engine.logic.console.commandSystem.MethodCommand; +import org.terasology.engine.logic.players.LocalPlayerSystem; +import org.terasology.engine.rendering.ShaderManager; +import org.terasology.engine.rendering.assets.material.Material; +import org.terasology.engine.rendering.backdrop.BackdropProvider; +import org.terasology.engine.rendering.cameras.Camera; +import org.terasology.engine.rendering.cameras.PerspectiveCamera; +import org.terasology.engine.rendering.dag.ModuleRendering; +import org.terasology.engine.rendering.dag.RenderGraph; +import org.terasology.engine.rendering.opengl.ScreenGrabber; +import org.terasology.engine.rendering.primitives.ChunkTessellator; +import org.terasology.engine.rendering.world.viewDistance.ViewDistance; +import org.terasology.engine.rust.EngineKernel; +import org.terasology.engine.utilities.Assets; +import org.terasology.engine.world.WorldProvider; +import org.terasology.engine.world.block.BlockManager; +import org.terasology.engine.world.chunks.ChunkProvider; +import org.terasology.engine.world.chunks.LodChunkProvider; +import org.terasology.engine.world.chunks.blockdata.ExtraBlockDataManager; +import org.terasology.engine.world.generator.ScalableWorldGenerator; +import org.terasology.engine.world.generator.WorldGenerator; +import org.terasology.math.TeraMath; + +import java.util.List; + +public class DeferredRenderer implements WorldRenderer { + /* + * Presumably, the eye height should be context.get(Config.class).getPlayer().getEyeHeight() above the ground plane. + * It's not, so for now, we use this factor to adjust for the disparity. + */ + private static final Logger logger = LoggerFactory.getLogger(DeferredRenderer.class); + private static final float GROUND_PLANE_HEIGHT_DISPARITY = -0.7f; + private RenderingModuleRegistry renderingModuleRegistry; + + private final RenderQueuesHelper renderQueues; + private final Context context; + private final BackdropProvider backdropProvider; + private final WorldProvider worldProvider; + private final RenderableWorld renderableWorld; + private final ShaderManager shaderManager; + private final EngineKernel kernel; + private final Camera playerCamera; + + private float timeSmoothedMainLightIntensity; + + private float millisecondsSinceRenderingStart; + private float secondsSinceLastFrame; + private int statChunkMeshEmpty; + private int statChunkNotReady; + private int statRenderedTriangles; + + private final RenderingConfig renderingConfig; + private final Console console; + + + /** + * Instantiates a WorldRenderer implementation. + *

+ * This particular implementation works as deferred shader. The scene is rendered multiple times per frame in a + * number of separate passes (each stored in GPU buffers) and the passes are combined throughout the rendering + * pipeline to calculate per-pixel lighting and other effects. + *

+ * Transparencies are handled through alpha rejection (i.e. ground plants) and alpha-based blending. An exception to + * this is water, which is handled separately to allow for reflections and refractions, if enabled. + *

+ * By the time it is fully instantiated this implementation is already connected to all the support objects it + * requires and is ready to render via the render(RenderingStage) method. + * + * @param context a context object, to obtain instances of classes such as the rendering config. + */ + public DeferredRenderer(Context context) { + this.context = context; + this.worldProvider = context.get(WorldProvider.class); + this.backdropProvider = context.get(BackdropProvider.class); + this.renderingConfig = context.get(Config.class).getRendering(); + this.shaderManager = context.get(ShaderManager.class); + this.kernel = context.get(EngineKernel.class); + playerCamera = new PerspectiveCamera(renderingConfig, context.get(DisplayDevice.class)); +// currentRenderingStage = RenderingStage.MONO; + // TODO: won't need localPlayerSystem here once camera is in the ES proper + LocalPlayerSystem localPlayerSystem = context.get(LocalPlayerSystem.class); + localPlayerSystem.setPlayerCamera(playerCamera); + + context.put(ChunkTessellator.class, new ChunkTessellator(this.kernel)); + + ChunkProvider chunkProvider = context.get(ChunkProvider.class); + ChunkTessellator chunkTessellator = context.get(ChunkTessellator.class); + BlockManager blockManager = context.get(BlockManager.class); + ExtraBlockDataManager extraDataManager = context.get(ExtraBlockDataManager.class); + Config config = context.get(Config.class); + + + WorldGenerator worldGenerator = context.get(WorldGenerator.class); + LodChunkProvider lodChunkProvider = null; + if (worldGenerator instanceof ScalableWorldGenerator) { + lodChunkProvider = new LodChunkProvider(chunkProvider, blockManager, extraDataManager, + (ScalableWorldGenerator) worldGenerator, chunkTessellator); + } + this.renderableWorld = new RenderableWorldImpl(this, lodChunkProvider, chunkProvider, chunkTessellator, worldProvider, config, playerCamera); + renderQueues = renderableWorld.getRenderQueues(); + + initRenderingSupport(); + + initRenderingModules(); + + console = context.get(Console.class); + MethodCommand.registerAvailable(this, console, context); + } + + private void initRenderingSupport() { + ScreenGrabber screenGrabber = new ScreenGrabber(context); + context.put(ScreenGrabber.class, screenGrabber); + +// displayResolutionDependentFbo = new DisplayResolutionDependentFbo( +// context.get(Config.class).getRendering(), screenGrabber, context.get(DisplayDevice.class)); +// context.put(DisplayResolutionDependentFbo.class, displayResolutionDependentFbo); + + shaderManager.initShaders(); + + context.put(WorldRenderer.class, this); + context.put(RenderQueuesHelper.class, renderQueues); + context.put(RenderableWorld.class, renderableWorld); + } + + + private void initRenderingModules() { + renderingModuleRegistry = context.get(RenderingModuleRegistry.class); + + // registry not populated by new ModuleRendering instances in UI, populate now + if (renderingModuleRegistry.getOrderedRenderingModules().isEmpty()) { + List renderingModules = renderingModuleRegistry.updateRenderingModulesOrder( + context.get(ModuleManager.class).getEnvironment(), context); + if (renderingModules.isEmpty()) { + GameEngine gameEngine = context.get(GameEngine.class); + gameEngine.changeState(new StateMainMenu("No rendering module loaded, unable to render. Try enabling " + + "CoreRendering.")); + } + } else { // registry populated by new ModuleRendering instances in UI + // Switch module's context from gamecreation subcontext to gamerunning context + renderingModuleRegistry.updateModulesContext(context); + } + + for (ModuleRendering moduleRenderingInstance : renderingModuleRegistry.getOrderedRenderingModules()) { + if (moduleRenderingInstance.isEnabled()) { + logger.info(String.format("\nInitialising rendering class %s from %s module.\n", + moduleRenderingInstance.getClass().getSimpleName(), + moduleRenderingInstance.getProvidingModule())); + moduleRenderingInstance.initialise(); + } + } + + requestTaskListRefresh(); + } + + + @Override + public float getSecondsSinceLastFrame() { + return secondsSinceLastFrame; + } + + @Override + public Material getMaterial(String assetId) { + return Assets.getMaterial(assetId).orElseThrow(() -> + new RuntimeException("Failed to resolve required asset: '" + assetId + "'")); + } + + @Override + public void onChunkLoaded(Vector3ic pos) { + renderableWorld.onChunkLoaded(pos); + } + + @Override + public void onChunkUnloaded(Vector3ic pos) { + renderableWorld.onChunkUnloaded(pos); + } + + @Override + public boolean pregenerateChunks() { + return renderableWorld.pregenerateChunks(); + } + + @Override + public void update(float deltaInSeconds) { + secondsSinceLastFrame += deltaInSeconds; + } + + @Override + public void increaseTrianglesCount(int increase) { + statRenderedTriangles += increase; + } + + @Override + public void increaseNotReadyChunkCount(int increase) { + statChunkNotReady += increase; + } + + + /** + * TODO: update javadocs This method triggers the execution of the rendering pipeline and, eventually, sends the + * output to the display or to a file, when grabbing a screenshot. + *

+ * In this particular implementation this method can be called once per frame, when rendering to a standard display, + * or twice, each time with a different rendering stage, when rendering to the head mounted display. + *

+ * PerformanceMonitor.startActivity/endActivity statements are used in this method and in those it executes, to + * provide statistics regarding the ongoing rendering and its individual steps (i.e. rendering shadows, reflections, + * 2D filters...). + * + * @param renderingStage "MONO" for standard rendering and "LEFT_EYE" or "RIGHT_EYE" for stereoscopic + * displays. + */ + @Override + public void render(RenderingStage renderingStage) { + statChunkMeshEmpty = 0; + statChunkNotReady = 0; + statRenderedTriangles = 0; + + timeSmoothedMainLightIntensity = TeraMath.lerp(timeSmoothedMainLightIntensity, + getMainLightIntensityAt(playerCamera.getPosition()), secondsSinceLastFrame); + + playerCamera.update(secondsSinceLastFrame); + + renderableWorld.update(); + secondsSinceLastFrame = 0; + millisecondsSinceRenderingStart += secondsSinceLastFrame * 1000; // updates the variable animations are + + playerCamera.updateFrustum(); + + // this line needs to be here as deep down it relies on the camera's frustrum, updated just above. + renderableWorld.queueVisibleChunks(true); + + //TODO: implement rendering logic + + playerCamera.updatePrevViewProjectionMatrix(); + } + + @Override + public void requestTaskListRefresh() { + } + + @Override + public boolean isFirstRenderingStageForCurrentFrame() { + return true; + } + + /** + * Disposes of support objects used by this implementation. + */ + @Override + public void dispose() { + renderableWorld.dispose(); + worldProvider.dispose(); + } + + @Override + public void setViewDistance(ViewDistance viewDistance, int chunkLods) { + renderableWorld.updateChunksInProximity(viewDistance, chunkLods); + } + + @Override + public float getTimeSmoothedMainLightIntensity() { + return timeSmoothedMainLightIntensity; + } + + @Override + public float getRenderingLightIntensityAt(Vector3f pos) { + float rawLightValueSun = worldProvider.getSunlight(pos) / 15.0f; + float rawLightValueBlock = worldProvider.getLight(pos) / 15.0f; + + float lightValueSun = + (float) Math.pow(BLOCK_LIGHT_SUN_POW, (1.0f - rawLightValueSun) * 16.0) * rawLightValueSun; + lightValueSun *= backdropProvider.getDaylight(); + // TODO: Hardcoded factor and value to compensate for daylight tint and night brightness + lightValueSun *= 0.9f; + lightValueSun += 0.05f; + + float lightValueBlock = + (float) Math.pow(BLOCK_LIGHT_POW, (1.0f - (double) rawLightValueBlock) * 16.0f) * rawLightValueBlock * BLOCK_INTENSITY_FACTOR; + + return Math.max(lightValueBlock, lightValueSun); + } + + @Override + public float getMainLightIntensityAt(Vector3f position) { + return backdropProvider.getDaylight() * worldProvider.getSunlight(position) / 15.0f; + } + + @Override + public float getBlockLightIntensityAt(Vector3f position) { + return worldProvider.getLight(position) / 15.0f; + } + + @Override + public String getMetrics() { + String stringToReturn = ""; + stringToReturn += renderableWorld.getMetrics(); + stringToReturn += "Empty Mesh Chunks: "; + stringToReturn += statChunkMeshEmpty; + stringToReturn += "\n"; + stringToReturn += "Unready Chunks: "; + stringToReturn += statChunkNotReady; + stringToReturn += "\n"; + stringToReturn += "Rendered Triangles: "; + stringToReturn += statRenderedTriangles; + stringToReturn += "\n"; + return stringToReturn; + } + + @Override + public float getMillisecondsSinceRenderingStart() { + return millisecondsSinceRenderingStart; + } + + @Override + public Camera getActiveCamera() { + return playerCamera; + } + + @Override + public RenderingStage getCurrentRenderStage() { + return RenderingStage.LEFT_EYE; + } + + @Override + public RenderGraph getRenderGraph() { + return null; + } + +} diff --git a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java index e513ac59243..b57317c1521 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java +++ b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java @@ -92,7 +92,6 @@ class RenderableWorldImpl implements RenderableWorld { new PriorityQueue<>(MAX_LOADABLE_CHUNKS, frontToBackComparator), new PriorityQueue<>(MAX_LOADABLE_CHUNKS, backToFrontComparator)); - } @Override diff --git a/engine/src/main/java/org/terasology/engine/rendering/world/WorldRendererImpl.java b/engine/src/main/java/org/terasology/engine/rendering/world/WorldRendererImpl.java index f2462052736..51c0f427dd4 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/world/WorldRendererImpl.java +++ b/engine/src/main/java/org/terasology/engine/rendering/world/WorldRendererImpl.java @@ -129,7 +129,8 @@ public WorldRendererImpl(Context context) { LocalPlayerSystem localPlayerSystem = context.get(LocalPlayerSystem.class); localPlayerSystem.setPlayerCamera(playerCamera); - context.put(ChunkTessellator.class, new ChunkTessellator()); + context.put(ChunkTessellator.class, new ChunkTessellator(null + )); ChunkProvider chunkProvider = context.get(ChunkProvider.class); ChunkTessellator chunkTessellator = context.get(ChunkTessellator.class); From f3efca57c11c61131991191e02edcb6fbb73c011 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sat, 29 Jul 2023 08:09:05 -0700 Subject: [PATCH 13/13] Update engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java Co-authored-by: BenjaminAmos <24301287+BenjaminAmos@users.noreply.github.com> --- .../terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java | 1 + 1 file changed, 1 insertion(+) diff --git a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java index f2c333d3811..6e4d6d90877 100644 --- a/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java +++ b/engine/src/main/java/org/terasology/engine/core/subsystem/lwjgl/LwjglGraphics.java @@ -143,6 +143,7 @@ public void postInitialise(Context rootContext) { GLFW.glfwWindowHint(GLFW.GLFW_COCOA_GRAPHICS_SWITCHING, GLFW.GLFW_TRUE); GLFW.glfwWindowHint(GLFW.GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW.GLFW_FALSE); GLFW.glfwWindowHint(GLFW.GLFW_DEPTH_BITS, config.getPixelFormat()); + GLFW.glfwWindowHint(GLFW.GLFW_CLIENT_API, GLFW.GLFW_NO_API); if (config.getDebug().isEnabled()) { GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_DEBUG_CONTEXT, GLFW.GLFW_TRUE); }