diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 67983a49..81a24224 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -3,6 +3,7 @@ "redhat.java", "vscjava.vscode-java-debug", "slevesque.shader", - "vscjava.vscode-java-test" + "vscjava.vscode-java-test", + "dtoplak.vscode-glsllint" ] } \ No newline at end of file diff --git a/assets/Shaders/core/postprocessing/postprocessing.fs b/assets/Shaders/core/postprocessing/postprocessing.fs new file mode 100644 index 00000000..a6949055 --- /dev/null +++ b/assets/Shaders/core/postprocessing/postprocessing.fs @@ -0,0 +1,72 @@ +#version 450 core + +//the texture coordinates of the screen +in vec2 textureCoords; + +// shader outputs +layout (location = 0) out vec4 frag; + + +// +//Uniforms +// + +// color accumulation buffer +layout (binding = 0) uniform sampler2D screenTexture; + +//Controls whether blur is applied or not +uniform int applyBlur; + + + +// +//Consts +// + +//How far to pull pixels from +const float offset = 1.0 / 300.0; + +//offsets for kernel sampling +const vec2 kernelOffsets[9] = vec2[]( + vec2(-offset, offset), // top-left + vec2( 0.0f, offset), // top-center + vec2( offset, offset), // top-right + vec2(-offset, 0.0f), // center-left + vec2( 0.0f, 0.0f), // center-center + vec2( offset, 0.0f), // center-right + vec2(-offset, -offset), // bottom-left + vec2( 0.0f, -offset), // bottom-center + vec2( offset, -offset) // bottom-right +); + +const float blurKernel[9] = float[]( + 1.0 / 16, 2.0 / 16, 1.0 / 16, + 2.0 / 16, 4.0 / 16, 2.0 / 16, + 1.0 / 16, 2.0 / 16, 1.0 / 16 +); + + + +// +//main +// +void main(){ + vec3 outputColor = vec3(texture(screenTexture,textureCoords.st)); + + //kernel samples + vec3 sampleTex[9]; + + // + //Blur + if(applyBlur > 0){ + for(int i = 0; i < 9; i++){ + sampleTex[i] = vec3(texture(screenTexture, textureCoords.st + kernelOffsets[i])); + } + outputColor = vec3(0.0); + for(int i = 0; i < 9; i++){ + outputColor = outputColor + sampleTex[i] * blurKernel[i]; + } + } + + frag = vec4(outputColor, 1.0); +} \ No newline at end of file diff --git a/assets/Shaders/core/postprocessing/postprocessing.vs b/assets/Shaders/core/postprocessing/postprocessing.vs new file mode 100644 index 00000000..d94408d8 --- /dev/null +++ b/assets/Shaders/core/postprocessing/postprocessing.vs @@ -0,0 +1,12 @@ +#version 450 core + +// shader inputs +layout (location = 0) in vec3 position; +layout (location = 1) in vec2 rawTextureCoords; + +out vec2 textureCoords; + +void main(){ + textureCoords = rawTextureCoords; + gl_Position = vec4(position, 1.0f); +} \ No newline at end of file diff --git a/buildNumber.properties b/buildNumber.properties index 01f72fed..6d159426 100644 --- a/buildNumber.properties +++ b/buildNumber.properties @@ -1,3 +1,3 @@ #maven.buildNumber.plugin properties file -#Mon Sep 16 16:11:24 EDT 2024 -buildNumber=330 +#Mon Sep 16 18:21:53 EDT 2024 +buildNumber=331 diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index e6b0fa8a..fa8e9ad9 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -776,6 +776,9 @@ New character customizer component (09/16/2024) Fix Scrollable position miscalculation Fix equipped item packet not being sent to creature's player +Component-ify natural and equip inventory menus +Post Processing Pipeline w/ blur +Blur on open inventory/main menu in game # TODO diff --git a/src/main/java/electrosphere/controls/ControlHandler.java b/src/main/java/electrosphere/controls/ControlHandler.java index 1726e0b9..54eea293 100644 --- a/src/main/java/electrosphere/controls/ControlHandler.java +++ b/src/main/java/electrosphere/controls/ControlHandler.java @@ -102,6 +102,7 @@ import electrosphere.menu.WindowUtils; import electrosphere.menu.debug.ImGuiWindowMacros; import electrosphere.menu.ingame.MenuGeneratorsInGame; import electrosphere.menu.ingame.MenuGeneratorsInventory; +import electrosphere.renderer.ui.components.PlayerInventoryWindow; import electrosphere.renderer.ui.elements.Window; import electrosphere.renderer.ui.events.ClickEvent; import electrosphere.renderer.ui.events.KeyboardEvent; @@ -969,6 +970,7 @@ public class ControlHandler { if(Globals.virtualAudioSourceManager != null){ Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/openMenu.ogg", VirtualAudioSourceType.UI, false); } + Globals.renderingEngine.getPostProcessingPipeline().setApplyBlur(true); }}); controls.get(DATA_STRING_INPUT_CODE_IN_GAME_MAIN_MENU).setRepeatTimeout(0.5f * Main.targetFrameRate); @@ -981,7 +983,7 @@ public class ControlHandler { if(InventoryUtils.hasNaturalInventory(Globals.playerEntity) && Globals.elementService.getWindow(WindowUtils.getInventoryWindowID(InventoryUtils.getNaturalInventory(Globals.playerEntity).getId())) == null){ //create window UnrelationalInventoryState inventory = InventoryUtils.getNaturalInventory(Globals.playerEntity); - Window mainMenuWindow = MenuGeneratorsInventory.createNaturalInventoryMenu(inventory); + Window mainMenuWindow = PlayerInventoryWindow.createPlayerInventoryWindow(Globals.playerEntity); //register Globals.elementService.registerWindow(WindowUtils.getInventoryWindowID(inventory.getId()), mainMenuWindow); //make visible @@ -992,10 +994,12 @@ public class ControlHandler { if(Globals.virtualAudioSourceManager != null){ Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/openMenu.ogg", VirtualAudioSourceType.UI, false); } + Globals.renderingEngine.getPostProcessingPipeline().setApplyBlur(true); // Globals.openInventoriesCount++; } else if(InventoryUtils.hasNaturalInventory(Globals.playerEntity) && Globals.elementService.getWindow(WindowUtils.getInventoryWindowID(InventoryUtils.getNaturalInventory(Globals.playerEntity).getId())) != null){ Globals.elementService.closeWindow(WindowUtils.getInventoryWindowID(InventoryUtils.getNaturalInventory(Globals.playerEntity).getId())); + Globals.renderingEngine.getPostProcessingPipeline().setApplyBlur(false); } }}); controls.get(INPUT_CODE_INVENTORY_OPEN).setRepeatTimeout(0.5f * Main.targetFrameRate); @@ -1019,10 +1023,12 @@ public class ControlHandler { if(Globals.virtualAudioSourceManager != null){ Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/openMenu.ogg", VirtualAudioSourceType.UI, false); } + Globals.renderingEngine.getPostProcessingPipeline().setApplyBlur(true); // Globals.openInventoriesCount++; } else if(InventoryUtils.hasEquipInventory(Globals.playerEntity) && Globals.elementService.getWindow(WindowStrings.WINDOW_CHARACTER) != null){ Globals.elementService.closeWindow(WindowStrings.WINDOW_CHARACTER); + Globals.renderingEngine.getPostProcessingPipeline().setApplyBlur(false); } }}); controls.get(INPUT_CODE_CHARACTER_OPEN).setRepeatTimeout(0.5f * Main.targetFrameRate); diff --git a/src/main/java/electrosphere/entity/state/inventory/InventoryUtils.java b/src/main/java/electrosphere/entity/state/inventory/InventoryUtils.java index 2239e8d2..566a1e10 100644 --- a/src/main/java/electrosphere/entity/state/inventory/InventoryUtils.java +++ b/src/main/java/electrosphere/entity/state/inventory/InventoryUtils.java @@ -25,11 +25,33 @@ import electrosphere.server.utils.ServerScriptUtils; public class InventoryUtils { + /** + * Checks if the entity has a natural inventory + * @param target The entity + * @return The inventory if it exists, null otherwise + */ public static boolean hasNaturalInventory(Entity target){ return target.containsKey(EntityDataStrings.NATURAL_INVENTORY); } + /** + * Sets the natural inventory of the entity + * @param target The entity + * @param inventoryState The inventory + */ + public static void setNaturalInventory(Entity target, UnrelationalInventoryState inventoryState){ + target.putData(EntityDataStrings.NATURAL_INVENTORY, inventoryState); + } + + /** + * Gets the natural inventory of the entity + * @param target The entity + * @return The inventory if it exists, null otherwise + */ public static UnrelationalInventoryState getNaturalInventory(Entity target){ + if(!target.containsKey(EntityDataStrings.NATURAL_INVENTORY)){ + return null; + } return (UnrelationalInventoryState)target.getData(EntityDataStrings.NATURAL_INVENTORY); } @@ -37,7 +59,24 @@ public class InventoryUtils { return target.containsKey(EntityDataStrings.EQUIP_INVENTORY); } + /** + * Sets the equipment inventory of the entity + * @param target The target + * @param inventoryState The inventory + */ + public static void setEquipInventory(Entity target, RelationalInventoryState inventoryState){ + target.putData(EntityDataStrings.EQUIP_INVENTORY, inventoryState); + } + + /** + * Gets the equipment inventory of the entity + * @param target The entity + * @return The inventory if it exists, null otherwise + */ public static RelationalInventoryState getEquipInventory(Entity target){ + if(!target.containsKey(EntityDataStrings.EQUIP_INVENTORY)){ + return null; + } return (RelationalInventoryState)target.getData(EntityDataStrings.EQUIP_INVENTORY); } @@ -47,6 +86,9 @@ public class InventoryUtils { * @return The inventory state behavior tree or null */ public static ClientInventoryState clientGetInventoryState(Entity target){ + if(!target.containsKey(EntityDataStrings.CLIENT_INVENTORY_STATE)){ + return null; + } return (ClientInventoryState)target.getData(EntityDataStrings.CLIENT_INVENTORY_STATE); } @@ -56,6 +98,9 @@ public class InventoryUtils { * @return The inventory state behavior tree or null */ public static ServerInventoryState serverGetInventoryState(Entity target){ + if(!target.containsKey(EntityDataStrings.SERVER_INVENTORY_STATE)){ + return null; + } return (ServerInventoryState)target.getData(EntityDataStrings.SERVER_INVENTORY_STATE); } diff --git a/src/main/java/electrosphere/game/data/creature/type/equip/EquipPoint.java b/src/main/java/electrosphere/game/data/creature/type/equip/EquipPoint.java index a4297de5..c551a05d 100644 --- a/src/main/java/electrosphere/game/data/creature/type/equip/EquipPoint.java +++ b/src/main/java/electrosphere/game/data/creature/type/equip/EquipPoint.java @@ -86,6 +86,14 @@ public class EquipPoint { return equipPointId; } + /** + * Sets the id of the equip point + * @param id The id + */ + public void setEquipPointId(String id){ + this.equipPointId = id; + } + /** * Gets the bone that can have the item attached to it (may not be defined depending on the type of equip point (think legs)) * @return the bone diff --git a/src/main/java/electrosphere/menu/debug/ImGuiRenderer.java b/src/main/java/electrosphere/menu/debug/ImGuiRenderer.java index e671f3d3..f417cc8d 100644 --- a/src/main/java/electrosphere/menu/debug/ImGuiRenderer.java +++ b/src/main/java/electrosphere/menu/debug/ImGuiRenderer.java @@ -1,6 +1,7 @@ package electrosphere.menu.debug; import electrosphere.engine.Globals; +import electrosphere.renderer.pipelines.PostProcessingPipeline; import electrosphere.renderer.pipelines.ShadowMapPipeline; import electrosphere.renderer.ui.imgui.ImGuiWindow; import electrosphere.renderer.ui.imgui.ImGuiWindow.ImGuiWindowCallback; @@ -36,6 +37,12 @@ public class ImGuiRenderer { shadowMapPipeline.setFarPlane(farPlaneArr[0]); } } + if(ImGui.collapsingHeader("Post Processing Pipeline")){ + PostProcessingPipeline postProcessingPipeline = Globals.renderingEngine.getPostProcessingPipeline(); + if(ImGui.button("Toggle Blur")){ + postProcessingPipeline.setApplyBlur(!postProcessingPipeline.isApplyingBlur()); + } + } } }); rendererWindow.setOpen(false); diff --git a/src/main/java/electrosphere/menu/ingame/MenuGeneratorsInventory.java b/src/main/java/electrosphere/menu/ingame/MenuGeneratorsInventory.java index f59c0d49..6aa7f3f8 100644 --- a/src/main/java/electrosphere/menu/ingame/MenuGeneratorsInventory.java +++ b/src/main/java/electrosphere/menu/ingame/MenuGeneratorsInventory.java @@ -508,12 +508,12 @@ public class MenuGeneratorsInventory { * Destroys the dummy panel */ public static void destroyDummyPanel(){ - // if(dummyPanel != null && dummyPanel.getParent() != null){ - // ContainerElement container = (ContainerElement)dummyPanel.getParent(); - // container.removeChild(dummyPanel); - // dummyPanel.destroy(); - // dummyPanel = null; - // } + if(dummyPanel != null && dummyPanel.getParent() != null){ + ContainerElement container = (ContainerElement)dummyPanel.getParent(); + container.removeChild(dummyPanel); + dummyPanel.destroy(); + dummyPanel = null; + } } } diff --git a/src/main/java/electrosphere/menu/mainmenu/MenuGeneratorsUITesting.java b/src/main/java/electrosphere/menu/mainmenu/MenuGeneratorsUITesting.java index 80f41427..0c6afee7 100644 --- a/src/main/java/electrosphere/menu/mainmenu/MenuGeneratorsUITesting.java +++ b/src/main/java/electrosphere/menu/mainmenu/MenuGeneratorsUITesting.java @@ -1,15 +1,25 @@ package electrosphere.menu.mainmenu; import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; import org.joml.Vector3f; import electrosphere.client.entity.camera.CameraEntityUtils; import electrosphere.engine.Globals; import electrosphere.engine.assetmanager.AssetDataStrings; +import electrosphere.entity.Entity; +import electrosphere.entity.EntityCreationUtils; +import electrosphere.entity.state.inventory.InventoryUtils; +import electrosphere.entity.state.inventory.RelationalInventoryState; +import electrosphere.entity.state.inventory.UnrelationalInventoryState; +import electrosphere.game.data.creature.type.equip.EquipPoint; import electrosphere.menu.WindowUtils; import electrosphere.renderer.actor.ActorUtils; import electrosphere.renderer.ui.components.CharacterCustomizer; +import electrosphere.renderer.ui.components.EquipmentInventoryPanel; +import electrosphere.renderer.ui.components.NaturalInventoryPanel; import electrosphere.renderer.ui.elements.ActorPanel; import electrosphere.renderer.ui.elements.Button; import electrosphere.renderer.ui.elements.FormElement; @@ -44,7 +54,9 @@ public class MenuGeneratorsUITesting { Arrays.asList(new String[]{ "Generic", "Slider", - "CharacterCustomizer" + "CharacterCustomizer", + "NaturalInventoryPanel", + "EquipInventoryPanel", }), (ValueChangeEvent event) -> { attachComponent(rVal,event.getAsString()); @@ -106,6 +118,24 @@ public class MenuGeneratorsUITesting { case "CharacterCustomizer": { formEl.addChild(CharacterCustomizer.createCharacterCustomizerPanel("human")); } break; + case "NaturalInventoryPanel": { + Entity ent = EntityCreationUtils.TEST_createEntity(); + UnrelationalInventoryState invent = UnrelationalInventoryState.createUnrelationalInventory(5); + InventoryUtils.setNaturalInventory(ent, invent); + formEl.addChild(NaturalInventoryPanel.createNaturalInventoryPanel(ent)); + } break; + case "EquipInventoryPanel": { + Entity ent = EntityCreationUtils.TEST_createEntity(); + List points = new LinkedList(); + for(int i = 0; i < 5; i++){ + EquipPoint equipPoint = new EquipPoint(); + equipPoint.setEquipPointId("equip point " + i); + points.add(equipPoint); + } + RelationalInventoryState invent = RelationalInventoryState.buildRelationalInventoryStateFromEquipList(points); + InventoryUtils.setEquipInventory(ent, invent); + formEl.addChild(EquipmentInventoryPanel.createEquipmentInventoryPanel(ent)); + } break; } } diff --git a/src/main/java/electrosphere/renderer/RenderingEngine.java b/src/main/java/electrosphere/renderer/RenderingEngine.java index 376f3794..40e99f69 100644 --- a/src/main/java/electrosphere/renderer/RenderingEngine.java +++ b/src/main/java/electrosphere/renderer/RenderingEngine.java @@ -1,11 +1,8 @@ package electrosphere.renderer; import static electrosphere.renderer.RenderUtils.createScreenTextureVAO; -import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; import static org.lwjgl.opengl.GL11.GL_ONE_MINUS_SRC_ALPHA; import static org.lwjgl.opengl.GL11.GL_SRC_ALPHA; -import static org.lwjgl.opengl.GL11.glClear; -import static org.lwjgl.opengl.GL11.glClearColor; import static org.lwjgl.opengl.GL30.GL_FRAMEBUFFER; import static org.lwjgl.opengl.GL30.GL_RENDERBUFFER; import static org.lwjgl.opengl.GL30.glBindRenderbuffer; @@ -40,6 +37,7 @@ import electrosphere.renderer.pipelines.ImGuiPipeline; import electrosphere.renderer.pipelines.MainContentNoOITPipeline; import electrosphere.renderer.pipelines.MainContentPipeline; import electrosphere.renderer.pipelines.NormalsForOutlinePipeline; +import electrosphere.renderer.pipelines.OutlineNormalsPipeline; import electrosphere.renderer.pipelines.PostProcessingPipeline; import electrosphere.renderer.pipelines.RenderScreenPipeline; import electrosphere.renderer.pipelines.ShadowMapPipeline; @@ -162,8 +160,9 @@ public class RenderingEngine { ShadowMapPipeline shadowMapPipeline = new ShadowMapPipeline(); VolumeBufferPipeline volumeBufferPipeline = new VolumeBufferPipeline(); NormalsForOutlinePipeline normalsForOutlinePipeline = new NormalsForOutlinePipeline(); - PostProcessingPipeline postProcessingPipeline = new PostProcessingPipeline(); + OutlineNormalsPipeline outlineNormalsPipeline = new OutlineNormalsPipeline(); CompositePipeline compositePipeline = new CompositePipeline(); + PostProcessingPipeline postProcessingPipeline = new PostProcessingPipeline(); UIPipeline uiPipeline = new UIPipeline(); RenderScreenPipeline renderScreenPipeline = new RenderScreenPipeline(); ImGuiPipeline imGuiPipeline; @@ -393,13 +392,8 @@ public class RenderingEngine { nearVolumeProjectionMatrix.setPerspective((float)(Globals.verticalFOV * Math.PI /180.0f), (float)Globals.WINDOW_WIDTH / (float)Globals.WINDOW_HEIGHT, 0.1f, 100); // - //Postprocessing textures and buffers + //Compositing textures and buffers // - /* - static Texture normalsOutlineTexture; - static Framebuffer normalsOutlineFrambuffer; - static ShaderProgram normalsOutlineShader; - */ try { normalsOutlineTexture = FramebufferUtils.generateScreenTextureColorAlpha(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY()); normalsOutlineFrambuffer = FramebufferUtils.generateScreenTextureFramebuffer(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY(), normalsOutlineTexture); @@ -414,6 +408,11 @@ public class RenderingEngine { // compositeAnimeOutline = ShaderProgram.loadSpecificShader("Shaders/core/anime/compositeAnimeOutline.vs", "Shaders/core/anime/compositeAnimeOutline.fs"); + // + //Post processing pipeline init + // + postProcessingPipeline.init(openGLState); + //instantiate light manager lightManager = new LightManager(); @@ -508,20 +507,16 @@ public class RenderingEngine { checkError(); firstPersonItemsPipeline.render(openGLState, renderPipelineState); checkError(); - postProcessingPipeline.render(openGLState, renderPipelineState); + outlineNormalsPipeline.render(openGLState, renderPipelineState); checkError(); compositePipeline.render(openGLState, renderPipelineState); checkError(); + postProcessingPipeline.render(openGLState, renderPipelineState); + checkError(); } - - //bind default FBO - openGLState.glBindFramebuffer(GL_FRAMEBUFFER,0); - - glClearColor(1.0f, 1.0f, 1.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); //Render the game framebuffer texture to a quad if(Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER){ @@ -647,6 +642,14 @@ public class RenderingEngine { return this.shadowMapPipeline; } + /** + * Gets the post processing pipeline + * @return The post processing pipeline + */ + public PostProcessingPipeline getPostProcessingPipeline(){ + return this.postProcessingPipeline; + } + /** * Gets the current opengl state * @return diff --git a/src/main/java/electrosphere/renderer/pipelines/OutlineNormalsPipeline.java b/src/main/java/electrosphere/renderer/pipelines/OutlineNormalsPipeline.java new file mode 100644 index 00000000..baa2f7c6 --- /dev/null +++ b/src/main/java/electrosphere/renderer/pipelines/OutlineNormalsPipeline.java @@ -0,0 +1,49 @@ +package electrosphere.renderer.pipelines; + +import org.lwjgl.opengl.GL40; + +import electrosphere.engine.Globals; +import electrosphere.renderer.OpenGLState; +import electrosphere.renderer.RenderPipelineState; +import electrosphere.renderer.RenderingEngine; +import electrosphere.renderer.shader.ShaderProgram; + +/** + * Post processing pipeline + */ +public class OutlineNormalsPipeline implements RenderPipeline { + + @Override + public void render(OpenGLState openGLState, RenderPipelineState renderPipelineState) { + Globals.profiler.beginCpuSample("OutlineNormalsPipeline.render"); + // + // Outline normals + // + + RenderingEngine.normalsOutlineFrambuffer.bind(openGLState); + ShaderProgram program = Globals.assetManager.fetchShader("Shaders/core/anime/outlineNormals.vs", null, "Shaders/core/anime/outlineNormals.fs"); + if(program != null){ + openGLState.setActiveShader(renderPipelineState, program); + + GL40.glBindVertexArray(RenderingEngine.screenTextureVAO); + + openGLState.glActiveTexture(GL40.GL_TEXTURE0); + openGLState.glBindTexture(GL40.GL_TEXTURE_2D, 0); + openGLState.glActiveTexture(GL40.GL_TEXTURE1); + openGLState.glBindTexture(GL40.GL_TEXTURE_2D, 0); + openGLState.glActiveTexture(GL40.GL_TEXTURE2); + openGLState.glBindTexture(GL40.GL_TEXTURE_2D, 0); + openGLState.glActiveTexture(GL40.GL_TEXTURE3); + openGLState.glBindTexture(GL40.GL_TEXTURE_2D, 0); + openGLState.glActiveTexture(GL40.GL_TEXTURE0); + openGLState.glBindTexture(GL40.GL_TEXTURE_2D, RenderingEngine.gameImageNormalsTexture.getTexturePointer()); + + GL40.glDrawArrays(GL40.GL_TRIANGLES, 0, 6); + GL40.glBindVertexArray(0); + } + + Globals.renderingEngine.defaultFramebuffer.bind(openGLState); + Globals.profiler.endCpuSample(); + } + +} diff --git a/src/main/java/electrosphere/renderer/pipelines/PostProcessingPipeline.java b/src/main/java/electrosphere/renderer/pipelines/PostProcessingPipeline.java index 1fc71c7a..30021233 100644 --- a/src/main/java/electrosphere/renderer/pipelines/PostProcessingPipeline.java +++ b/src/main/java/electrosphere/renderer/pipelines/PostProcessingPipeline.java @@ -3,47 +3,118 @@ package electrosphere.renderer.pipelines; import org.lwjgl.opengl.GL40; import electrosphere.engine.Globals; +import electrosphere.logger.LoggerInterface; import electrosphere.renderer.OpenGLState; import electrosphere.renderer.RenderPipelineState; import electrosphere.renderer.RenderingEngine; +import electrosphere.renderer.framebuffer.Framebuffer; +import electrosphere.renderer.framebuffer.FramebufferUtils; import electrosphere.renderer.shader.ShaderProgram; +import electrosphere.renderer.texture.Texture; /** - * Post processing pipeline + * */ public class PostProcessingPipeline implements RenderPipeline { + /** + * The shader to render with + */ + ShaderProgram postProcessingShader; + + /** + * The buffer to render post processing effects to + */ + Framebuffer postProcessBuffer; + + /** + * Controls whether blur is applied or not + */ + boolean applyBlur = false; + + /** + * Init the pipeline + */ + public void init(OpenGLState openGLState){ + postProcessingShader = ShaderProgram.loadSpecificShader("Shaders/core/postprocessing/postprocessing.vs", "Shaders/core/postprocessing/postprocessing.fs"); + Texture screenTextureColor = FramebufferUtils.generateScreenTextureColorAlpha(openGLState, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT); + Texture screenTextureDepth = FramebufferUtils.generateScreenTextureDepth(openGLState, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT); + try { + postProcessBuffer = FramebufferUtils.generateScreenTextureFramebuffer(openGLState, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT, screenTextureColor, screenTextureDepth); + } catch (Exception e){ + LoggerInterface.loggerRenderer.ERROR(e); + } + } + @Override public void render(OpenGLState openGLState, RenderPipelineState renderPipelineState) { Globals.profiler.beginCpuSample("PostProcessingPipeline.render"); // - // Outline normals + //Setup to render screen textures & bind screen framebuffer // - - RenderingEngine.normalsOutlineFrambuffer.bind(openGLState); - ShaderProgram program = Globals.assetManager.fetchShader("Shaders/core/anime/outlineNormals.vs", null, "Shaders/core/anime/outlineNormals.fs"); - if(program != null){ - openGLState.setActiveShader(renderPipelineState, program); + openGLState.glDepthTest(false); + openGLState.glBlend(false); + openGLState.glViewport(Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT); - GL40.glBindVertexArray(RenderingEngine.screenTextureVAO); - openGLState.glActiveTexture(GL40.GL_TEXTURE0); - openGLState.glBindTexture(GL40.GL_TEXTURE_2D, 0); - openGLState.glActiveTexture(GL40.GL_TEXTURE1); - openGLState.glBindTexture(GL40.GL_TEXTURE_2D, 0); - openGLState.glActiveTexture(GL40.GL_TEXTURE2); - openGLState.glBindTexture(GL40.GL_TEXTURE_2D, 0); - openGLState.glActiveTexture(GL40.GL_TEXTURE3); - openGLState.glBindTexture(GL40.GL_TEXTURE_2D, 0); - openGLState.glActiveTexture(GL40.GL_TEXTURE0); - openGLState.glBindTexture(GL40.GL_TEXTURE_2D, RenderingEngine.gameImageNormalsTexture.getTexturePointer()); + postProcessBuffer.bind(openGLState); + openGLState.setActiveShader(renderPipelineState, postProcessingShader); + RenderingEngine.screenFramebuffer.getTexture().bind(openGLState); - GL40.glDrawArrays(GL40.GL_TRIANGLES, 0, 6); - GL40.glBindVertexArray(0); + + // + //Set post processing data + // + if(applyBlur){ + openGLState.getActiveShader().setUniform(openGLState, "applyBlur", 1); + } else { + openGLState.getActiveShader().setUniform(openGLState, "applyBlur", 0); } + // + //Draw + // + GL40.glBindVertexArray(RenderingEngine.screenTextureVAO); + GL40.glDrawArrays(GL40.GL_TRIANGLES, 0, 6); + + + + + + + + // + //Close down pipeline + // + GL40.glBindVertexArray(0); Globals.renderingEngine.defaultFramebuffer.bind(openGLState); + + Globals.profiler.endCpuSample(); } + + /** + * Gets the framebuffer for this pipeline step + * @return The framebuffer + */ + public Framebuffer getFramebuffer(){ + return this.postProcessBuffer; + } + + /** + * Gets whether blur is being applied or not + * @return true if bluring, false otherwise + */ + public boolean isApplyingBlur(){ + return applyBlur; + } + + /** + * Sets whether blur will be applied or not + * @param applyBlur true to blur, false otherwise + */ + public void setApplyBlur(boolean applyBlur){ + this.applyBlur = applyBlur; + } } diff --git a/src/main/java/electrosphere/renderer/pipelines/RenderScreenPipeline.java b/src/main/java/electrosphere/renderer/pipelines/RenderScreenPipeline.java index 48bba8c1..26107842 100644 --- a/src/main/java/electrosphere/renderer/pipelines/RenderScreenPipeline.java +++ b/src/main/java/electrosphere/renderer/pipelines/RenderScreenPipeline.java @@ -1,6 +1,7 @@ package electrosphere.renderer.pipelines; import org.lwjgl.opengl.GL40; +import org.lwjgl.opengl.GL45; import electrosphere.engine.Globals; import electrosphere.renderer.OpenGLState; @@ -15,6 +16,11 @@ public class RenderScreenPipeline implements RenderPipeline { @Override public void render(OpenGLState openGLState, RenderPipelineState renderPipelineState) { Globals.profiler.beginCpuSample("RenderScreenPipeline.render"); + //bind default FBO + openGLState.glBindFramebuffer(GL45.GL_FRAMEBUFFER,0); + + GL45.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + GL45.glClear(GL45.GL_COLOR_BUFFER_BIT); // //unbind texture channels // @@ -43,32 +49,35 @@ public class RenderScreenPipeline implements RenderPipeline { GL40.glBindVertexArray(RenderingEngine.screenTextureVAO); //aaa switch(RenderingEngine.outputFramebuffer){ - case 0: - openGLState.glBindTexture(GL40.GL_TEXTURE_2D, RenderingEngine.screenFramebuffer.getTexture().getTexturePointer()); - break; - case 1: + case 0: { + openGLState.glBindTexture(GL40.GL_TEXTURE_2D, Globals.renderingEngine.getPostProcessingPipeline().getFramebuffer().getTexture().getTexturePointer()); + } break; + case 1: { openGLState.glBindTexture(GL40.GL_TEXTURE_2D, RenderingEngine.lightDepthBuffer.getDepthTexture().getTexturePointer()); - break; - case 2: + } break; + case 2: { openGLState.glBindTexture(GL40.GL_TEXTURE_2D, RenderingEngine.volumeDepthBackfaceTexture.getTexturePointer()); - break; - case 3: + } break; + case 3: { openGLState.glBindTexture(GL40.GL_TEXTURE_2D, RenderingEngine.volumeDepthFrontfaceTexture.getTexturePointer()); - break; - case 4: + } break; + case 4: { openGLState.glBindTexture(GL40.GL_TEXTURE_2D, RenderingEngine.transparencyAccumulatorTexture.getTexturePointer()); - break; - case 5: + } break; + case 5: { openGLState.glBindTexture(GL40.GL_TEXTURE_2D, RenderingEngine.gameImageNormalsTexture.getTexturePointer()); - break; - case 6: + } break; + case 6: { openGLState.glBindTexture(GL40.GL_TEXTURE_2D, RenderingEngine.normalsOutlineTexture.getTexturePointer()); - break; - case 7: + } break; + case 7: { + openGLState.glBindTexture(GL40.GL_TEXTURE_2D, RenderingEngine.screenFramebuffer.getTexture().getTexturePointer()); + } break; + case 8: { openGLState.setActiveShader(renderPipelineState, RenderingEngine.drawChannel); GL40.glUniform1f(GL40.glGetUniformLocation(openGLState.getActiveShader().getShaderId(), "channel"),4); openGLState.glBindTexture(GL40.GL_TEXTURE_2D, RenderingEngine.screenTextureDepth.getTexturePointer()); - break; + } break; } GL40.glDrawArrays(GL40.GL_TRIANGLES, 0, 6); GL40.glBindVertexArray(0); diff --git a/src/main/java/electrosphere/renderer/ui/ElementService.java b/src/main/java/electrosphere/renderer/ui/ElementService.java index 0dd5564e..7f1a7dd3 100644 --- a/src/main/java/electrosphere/renderer/ui/ElementService.java +++ b/src/main/java/electrosphere/renderer/ui/ElementService.java @@ -518,6 +518,9 @@ public class ElementService extends SignalServiceImpl { switch(signal.getType()){ case YOGA_APPLY: { Element target = (Element)signal.getData(); + if(target == null){ + throw new Error("You forgot to include an element with the signal!"); + } target.applyYoga(0, 0); rVal = true; } break; diff --git a/src/main/java/electrosphere/renderer/ui/components/EquipmentInventoryPanel.java b/src/main/java/electrosphere/renderer/ui/components/EquipmentInventoryPanel.java new file mode 100644 index 00000000..8c0ff1f9 --- /dev/null +++ b/src/main/java/electrosphere/renderer/ui/components/EquipmentInventoryPanel.java @@ -0,0 +1,261 @@ +package electrosphere.renderer.ui.components; + +import java.util.List; + +import electrosphere.audio.VirtualAudioSourceManager.VirtualAudioSourceType; +import electrosphere.engine.Globals; +import electrosphere.entity.Entity; +import electrosphere.entity.state.equip.ClientEquipState; +import electrosphere.entity.state.inventory.InventoryUtils; +import electrosphere.entity.state.inventory.RelationalInventoryState; +import electrosphere.entity.state.inventory.UnrelationalInventoryState; +import electrosphere.entity.types.item.ItemUtils; +import electrosphere.game.data.creature.type.equip.EquipPoint; +import electrosphere.logger.LoggerInterface; +import electrosphere.menu.WindowStrings; +import electrosphere.menu.WindowUtils; +import electrosphere.menu.ingame.MenuGeneratorsInventory; +import electrosphere.renderer.ui.elements.Div; +import electrosphere.renderer.ui.elements.ImagePanel; +import electrosphere.renderer.ui.elements.Label; +import electrosphere.renderer.ui.elementtypes.ClickableElement.ClickEventCallback; +import electrosphere.renderer.ui.elementtypes.ContainerElement; +import electrosphere.renderer.ui.elementtypes.DraggableElement.DragEventCallback; +import electrosphere.renderer.ui.elementtypes.Element; +import electrosphere.renderer.ui.events.ClickEvent; +import electrosphere.renderer.ui.events.DragEvent; + +/** + * Inventory panel showing an entity's equipment + */ +public class EquipmentInventoryPanel { + + /** + * The dummy panel + */ + static ImagePanel dummyPanel = null; + + + /** + * Creates the equipment inventory panel + * @param inventory The inventory + * @return The panel + */ + public static Element createEquipmentInventoryPanel(Entity entity){ + RelationalInventoryState inventory = InventoryUtils.getEquipInventory(entity); + + Div div = Div.createDiv(); + + div.setOnDragRelease(new DragEventCallback() {public boolean execute(DragEvent event){ + LoggerInterface.loggerUI.INFO("Character inventory received drag release event"); + if(Globals.draggedItem != null){ + if(Globals.dragSourceInventory instanceof UnrelationalInventoryState){ + UnrelationalInventoryState sourceInventory = (UnrelationalInventoryState)Globals.dragSourceInventory; + //null out global state + Globals.dragSourceInventory = null; + Globals.draggedItem = null; + //clear item container ui + WindowUtils.cleanItemDraggingWindow(); + //dummy panel handling + destroyDummyPanel(); + //rerender both inventories + //re-render inventory + WindowUtils.replaceWindow(WindowStrings.WINDOW_CHARACTER, MenuGeneratorsInventory.createCharacterInventoryMenu(inventory)); + //re-render inventory + WindowUtils.replaceWindow(WindowUtils.getInventoryWindowID(sourceInventory.getId()), MenuGeneratorsInventory.createNaturalInventoryMenu(sourceInventory)); + } + return false; + } + return true; + }}); + + div.setOnClick(new ClickEventCallback() {public boolean execute(ClickEvent event){ + WindowUtils.focusWindow(WindowStrings.WINDOW_CHARACTER); + return false; + }}); + + + //label 1 (inventory) + Label inventoryLabel = new Label(1.0f); + inventoryLabel.setText("CHARACTER"); + div.addChild(inventoryLabel); + + // int columns = 8; + // int columnWidth = 60; + // int rowHeight = 60; + int slotSpacing = 30; + + List slots = inventory.getSlots(); + int numSlots = slots.size(); + EquipPoint equipPoint = null; + // int numRows = (numSlots / 2) + (numSlots % 2 == 1 ? 1 : 0); + + int incrementer = 0; + for(int i = 0; i < numSlots; i++){ + String texturePath = "Textures/ui/uiFrame1.png"; + boolean hasItem = false; + String slotId = slots.get(i); + equipPoint = inventory.getEquipPointFromSlot(slotId); + if(!equipPoint.isCombinedPoint()){ + if(inventory.getItemSlot(slotId) != null){ + Entity currentItem = inventory.getItemSlot(slotId); + //get texture path from item + texturePath = ItemUtils.getItemIcon(currentItem); + //flag that this isn't an empty slot + hasItem = true; + } else if(inventory.getCombinedPoint(slotId) != null && inventory.hasItemInSlot(inventory.getCombinedPoint(slotId).getEquipPointId())){ + Entity currentItem = inventory.getItemSlot(inventory.getCombinedPoint(slotId).getEquipPointId()); + //get texture path from item + texturePath = ItemUtils.getItemIcon(currentItem); + //flag that this isn't an empty slot + hasItem = true; + equipPoint = inventory.getCombinedPoint(slotId); + slotId = equipPoint.getEquipPointId(); + } + if(!Globals.assetManager.hasLoadedTexture(texturePath)){ + Globals.assetManager.addTexturePathtoQueue(texturePath); + } + int panelWidth = 50; + int panelHeight = 50; + int posX = 20; + if((incrementer % 2) == 1){ + posX = posX + 400; + } + int posXf = posX; + int posY = 60 + (i / 2 * (panelHeight + slotSpacing)); + int posYf = posY; + int itemPosX = posX; + int itemPosY = posY; + ImagePanel panel = ImagePanel.createImagePanelAbsolute(posX,posY,panelWidth,panelHeight,texturePath); + if(hasItem == true){ + //literally just here to get around finality of variable within callback + String finalSlotId = slotId; + panel.setOnDragStart(new DragEventCallback() { + public boolean execute(DragEvent event){ + LoggerInterface.loggerUI.DEBUG("Drag start"); + Globals.dragSourceInventory = inventory; + Globals.draggedItem = inventory.getItemSlot(finalSlotId); + ContainerElement container = (ContainerElement)panel.getParent(); + container.removeChild(panel); + WindowUtils.pushItemIconToItemWindow(panel); + //add a dummy icon in place of the existing one + dummyPanel = ImagePanel.createImagePanelAbsolute(posXf,posYf,panelWidth,panelHeight,"Textures/ui/uiFrame1.png"); + container.addChild(dummyPanel); + //play sound effect + if(Globals.virtualAudioSourceManager != null){ + Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/inventoryGrabItem.ogg", VirtualAudioSourceType.UI, false); + } + return false; + }}); + panel.setOnDrag(new DragEventCallback() {public boolean execute(DragEvent event){ + // System.out.println("Drag"); + panel.setPositionX(event.getCurrentX() - panelWidth / 2); + panel.setPositionY(event.getCurrentY() - panelHeight / 2); + return false; + }}); + panel.setOnDragRelease(new DragEventCallback(){public boolean execute(DragEvent event){ + if(panel.getParent() != div){ + if(panel.getParent() != null){ + ContainerElement container = (ContainerElement)panel.getParent(); + container.removeChild(panel); + } + Globals.elementService.fireEvent(event, event.getCurrentX(), event.getCurrentY()); + div.addChild(panel); + } + //dummy panel handling + destroyDummyPanel(); + panel.setPositionX(div.getAbsoluteX() + itemPosX); + panel.setPositionY(div.getAbsoluteY() + itemPosY); + return false; + }}); + + } else { + int itemId = i; + panel.setOnDragRelease(new DragEventCallback(){public boolean execute(DragEvent event){ + // panel.setPositionX(posX); + // panel.setPositionY(posY); + if(Globals.dragSourceInventory instanceof UnrelationalInventoryState){ + UnrelationalInventoryState sourceInventory = (UnrelationalInventoryState) Globals.dragSourceInventory; + Entity item = Globals.draggedItem; + if(inventory.canEquipItemToSlot(item, slots.get(itemId))){ + //fire equip event to equip state + ClientEquipState equipState = ClientEquipState.getEquipState(Globals.playerEntity); + equipState.commandAttemptEquip(item,inventory.getEquipPointFromSlot(slots.get(itemId))); + //play sound effect + if(Globals.virtualAudioSourceManager != null){ + Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/inventorySlotItem.ogg", VirtualAudioSourceType.UI, false); + } + } else if(inventory.canEquipItemToCombinedSlot(item, slots.get(itemId))){ + EquipPoint combinedPoint = inventory.getCombinedPoint(slots.get(itemId)); + //fire equip event to equip state + ClientEquipState equipState = ClientEquipState.getEquipState(Globals.playerEntity); + equipState.commandAttemptEquip(item,combinedPoint); + //play sound effect + if(Globals.virtualAudioSourceManager != null){ + Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/inventorySlotItem.ogg", VirtualAudioSourceType.UI, false); + } + } + //update ui + Globals.dragSourceInventory = null; + Globals.draggedItem = null; + //clear item container ui + WindowUtils.cleanItemDraggingWindow(); + //dummy panel handling + destroyDummyPanel(); + //rerender both inventories + //re-render inventory + WindowUtils.replaceWindow(WindowStrings.WINDOW_CHARACTER, MenuGeneratorsInventory.createCharacterInventoryMenu(inventory)); + //re-render inventory + WindowUtils.replaceWindow(WindowUtils.getInventoryWindowID(sourceInventory.getId()), PlayerInventoryWindow.createPlayerInventoryWindow(Globals.playerEntity)); + } + //now the fun begins :) + //if transfer item + // remove item from current inventory + // place item in new inventory + // trigger recreation of the menu + //if drop item + // remove item from current inventory + // create item in world in front of character + // trigger recreation of the menu + //if neither of above + // replace item icon position to origin + // System.out.println("Release drag"); + //rebuild inventory windows + return false; + }}); + } + div.addChild(panel); + + //create the slot text + posX = 80; + if((incrementer % 2) == 1){ + posX = posX + 190; + } + posY = posY + 15; + Label slotText = new Label(0.7f); + slotText.setText(slots.get(i)); + slotText.setPositionX(posX); + slotText.setPositionY(posY); + slotText.setAbsolutePosition(true); + div.addChild(slotText); + + incrementer++; + } + } + + return div; + } + + /** + * Destroys the dummy panel + */ + public static void destroyDummyPanel(){ + if(dummyPanel != null && dummyPanel.getParent() != null){ + ContainerElement container = (ContainerElement)dummyPanel.getParent(); + container.removeChild(dummyPanel); + dummyPanel.destroy(); + dummyPanel = null; + } + } + +} diff --git a/src/main/java/electrosphere/renderer/ui/components/NaturalInventoryPanel.java b/src/main/java/electrosphere/renderer/ui/components/NaturalInventoryPanel.java new file mode 100644 index 00000000..a222622c --- /dev/null +++ b/src/main/java/electrosphere/renderer/ui/components/NaturalInventoryPanel.java @@ -0,0 +1,222 @@ +package electrosphere.renderer.ui.components; + +import electrosphere.audio.VirtualAudioSourceManager.VirtualAudioSourceType; +import electrosphere.engine.Globals; +import electrosphere.entity.Entity; +import electrosphere.entity.state.equip.ClientEquipState; +import electrosphere.entity.state.inventory.InventoryUtils; +import electrosphere.entity.state.inventory.RelationalInventoryState; +import electrosphere.entity.state.inventory.UnrelationalInventoryState; +import electrosphere.entity.types.item.ItemUtils; +import electrosphere.logger.LoggerInterface; +import electrosphere.menu.WindowStrings; +import electrosphere.menu.WindowUtils; +import electrosphere.menu.ingame.MenuGeneratorsInventory; +import electrosphere.renderer.ui.elements.Div; +import electrosphere.renderer.ui.elements.ImagePanel; +import electrosphere.renderer.ui.elements.Label; +import electrosphere.renderer.ui.elementtypes.ClickableElement.ClickEventCallback; +import electrosphere.renderer.ui.elementtypes.ContainerElement; +import electrosphere.renderer.ui.elementtypes.DraggableElement.DragEventCallback; +import electrosphere.renderer.ui.elementtypes.Element; +import electrosphere.renderer.ui.events.ClickEvent; +import electrosphere.renderer.ui.events.DragEvent; + +/** + * An inventory panel showing a natural inventory + */ +public class NaturalInventoryPanel { + + /** + * The dummy panel + */ + static ImagePanel dummyPanel = null; + + /** + * Creates the natural inventory panel + * @param entity The entity who has the inventory + * @return The panel element + */ + public static Element createNaturalInventoryPanel(Entity entity){ + UnrelationalInventoryState inventory = InventoryUtils.getNaturalInventory(entity); + + + Div div = Div.createDiv(); + + div.setOnDragRelease(new DragEventCallback() {public boolean execute(DragEvent event){ + LoggerInterface.loggerUI.INFO("Natural inventory received drag release event"); + if(Globals.draggedItem != null){ + if(Globals.dragSourceInventory != inventory){ + if(Globals.dragSourceInventory instanceof UnrelationalInventoryState){ + UnrelationalInventoryState sourceInventory = (UnrelationalInventoryState)Globals.dragSourceInventory; + //transfer item + // sourceInventory.removeItem(Globals.draggedItem); + // inventory.addItem(Globals.draggedItem); + // //null out global state + // Globals.dragSourceInventory = null; + // Globals.draggedItem = null; + Entity item = Globals.draggedItem; + if(ClientEquipState.hasEquipState(entity) && InventoryUtils.hasEquipInventory(entity)){ + RelationalInventoryState equipInventory = InventoryUtils.getEquipInventory(entity); + ClientEquipState equipState = ClientEquipState.getEquipState(entity); + equipState.commandAttemptUnequip(equipInventory.getItemSlot(item)); + } + //clear item container ui + WindowUtils.cleanItemDraggingWindow(); + //dummy panel handling + destroyDummyPanel(); + //rerender both inventories + //re-render inventory + WindowUtils.replaceWindow(WindowUtils.getInventoryWindowID(inventory.getId()), PlayerInventoryWindow.createPlayerInventoryWindow(Globals.playerEntity)); + //re-render inventory + WindowUtils.replaceWindow(WindowUtils.getInventoryWindowID(sourceInventory.getId()), PlayerInventoryWindow.createPlayerInventoryWindow(Globals.playerEntity)); + } + } else { + //clear ui + WindowUtils.cleanItemDraggingWindow(); + //dummy panel handling + destroyDummyPanel(); + //re-render inventory + WindowUtils.replaceWindow(WindowUtils.getInventoryWindowID(inventory.getId()), PlayerInventoryWindow.createPlayerInventoryWindow(Globals.playerEntity)); + } + return false; + } + return true; + }}); + + div.setOnClick(new ClickEventCallback() {public boolean execute(ClickEvent event){ + WindowUtils.focusWindow(WindowStrings.WINDOW_MENU_INVENTORY); + return false; + }}); + + + //label 1 (inventory) + div.addChild(Label.createLabel("INVENTORY")); + + int columns = 8; + int columnWidth = 60; + int rowHeight = 60; + for(int i = 0; i < inventory.getCapacity(); i++){ + String texturePath = "Textures/ui/uiFrame1.png"; + boolean hasItem = false; + if(i < inventory.getItems().size()){ + Entity currentItem = inventory.getItems().get(i); + //get texture path from item + texturePath = ItemUtils.getItemIcon(currentItem); + //flag that this isn't an empty slot + hasItem = true; + } + if(!Globals.assetManager.hasLoadedTexture(texturePath)){ + Globals.assetManager.addTexturePathtoQueue(texturePath); + } + int posX = (10 + i % columns * columnWidth); + int posY = 60 + (i / columns * rowHeight); + int posXf = posX; + int posYf = posY; + int itemPosX = posX; + int itemPosY = posY; + int panelWidth = 50; + int panelHeight = 50; + ImagePanel panel = ImagePanel.createImagePanelAbsolute(posX,posY,panelWidth,panelHeight,texturePath); + if(hasItem == true){ + int itemId = i; + panel.setOnDragStart(new DragEventCallback() {public boolean execute(DragEvent event){ + // System.out.println("Drag start"); + Globals.dragSourceInventory = inventory; + Globals.draggedItem = inventory.getItems().get(itemId); + ContainerElement container = (ContainerElement)panel.getParent(); + container.removeChild(panel); + WindowUtils.pushItemIconToItemWindow(panel); + //add a dummy icon in place of the existing one + dummyPanel = ImagePanel.createImagePanelAbsolute(posXf,posYf,panelWidth,panelHeight,"Textures/ui/uiFrame1.png"); + container.addChild(dummyPanel); + //play sound effect + if(Globals.virtualAudioSourceManager != null){ + Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/inventoryGrabItem.ogg", VirtualAudioSourceType.UI, false); + } + return false; + }}); + panel.setOnDrag(new DragEventCallback() {public boolean execute(DragEvent event){ + // System.out.println("Drag"); + panel.setPositionX(event.getCurrentX() - panelWidth / 2); + panel.setPositionY(event.getCurrentY() - panelHeight / 2); + return false; + }}); + panel.setOnDragRelease(new DragEventCallback(){public boolean execute(DragEvent event){ + if(panel.getParent() != div){ + if(panel.getParent() != null){ + ContainerElement container = (ContainerElement)panel.getParent(); + container.removeChild(panel); + } + div.addChild(panel); + Globals.elementService.fireEvent(event, event.getCurrentX(), event.getCurrentY()); + } + //dummy panel handling + destroyDummyPanel(); + panel.setPositionX(div.getAbsoluteX() + itemPosX); + panel.setPositionY(div.getAbsoluteY() + itemPosY); + return false; + }}); + } else { + panel.setOnDragRelease(new DragEventCallback(){public boolean execute(DragEvent event){ + if(Globals.dragSourceInventory instanceof RelationalInventoryState){ + RelationalInventoryState sourceInventory = (RelationalInventoryState) Globals.dragSourceInventory; + Entity item = Globals.draggedItem; + if(ClientEquipState.hasEquipState(entity) && InventoryUtils.hasEquipInventory(entity)){ + RelationalInventoryState equipInventory = InventoryUtils.getEquipInventory(entity); + ClientEquipState equipState = ClientEquipState.getEquipState(entity); + equipState.commandAttemptUnequip(equipInventory.getItemSlot(item)); + } + //update ui + // Globals.dragSourceInventory = null; + // Globals.draggedItem = null; + //clear item container ui + WindowUtils.cleanItemDraggingWindow(); + //dummy panel handling + destroyDummyPanel(); + //rerender both inventories + //re-render inventory + WindowUtils.replaceWindow(WindowStrings.WINDOW_CHARACTER, MenuGeneratorsInventory.createCharacterInventoryMenu(sourceInventory)); + //re-render inventory + WindowUtils.replaceWindow(WindowUtils.getInventoryWindowID(inventory.getId()), PlayerInventoryWindow.createPlayerInventoryWindow(Globals.playerEntity)); + //play sound effect + if(Globals.virtualAudioSourceManager != null){ + Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/inventorySlotItem.ogg", VirtualAudioSourceType.UI, false); + } + } + //now the fun begins :) + //if transfer item + // remove item from current inventory + // place item in new inventory + // trigger recreation of the menu + //if drop item + // remove item from current inventory + // create item in world in front of character + // trigger recreation of the menu + //if neither of above + // replace item icon position to origin + // System.out.println("Release drag"); + return false; + }}); + } + // imagePanel.setWidth(width); + // imagePanel.setHeight(height); + // imagePanel.setTexture(Globals.assetManager.fetchTexture(Globals.blackTexture)); + div.addChild(panel); + } + return div; + } + + /** + * Destroys the dummy panel + */ + public static void destroyDummyPanel(){ + if(dummyPanel != null && dummyPanel.getParent() != null){ + ContainerElement container = (ContainerElement)dummyPanel.getParent(); + container.removeChild(dummyPanel); + dummyPanel.destroy(); + dummyPanel = null; + } + } + +} diff --git a/src/main/java/electrosphere/renderer/ui/components/PlayerInventoryWindow.java b/src/main/java/electrosphere/renderer/ui/components/PlayerInventoryWindow.java new file mode 100644 index 00000000..b300c87e --- /dev/null +++ b/src/main/java/electrosphere/renderer/ui/components/PlayerInventoryWindow.java @@ -0,0 +1,55 @@ +package electrosphere.renderer.ui.components; + +import electrosphere.engine.Globals; +import electrosphere.engine.signal.Signal.SignalType; +import electrosphere.entity.Entity; +import electrosphere.entity.state.inventory.InventoryUtils; +import electrosphere.renderer.ui.elements.Window; +import electrosphere.renderer.ui.elementtypes.ContainerElement.YogaAlignment; +import electrosphere.renderer.ui.elementtypes.ContainerElement.YogaJustification; + +/** + * The player's inventory + */ +public class PlayerInventoryWindow { + + /** + * Minimum width of the component + */ + public static final int MIN_WIDTH = 500; + + /** + * Minimum height of the component + */ + public static final int MIN_HEIGHT = 500; + + /** + * Creates a character customizer panel + * @param race The race of the character + * @return The panel component + */ + public static Window createPlayerInventoryWindow(Entity entity){ + int width = 500; + int height = 500; + + + Window rVal = Window.createExpandableCenterAligned(Globals.renderingEngine.getOpenGLState(), width, height); + rVal.setParentAlignItem(YogaAlignment.Center); + rVal.setParentJustifyContent(YogaJustification.Center); + + if(InventoryUtils.hasNaturalInventory(entity)){ + rVal.addChild(NaturalInventoryPanel.createNaturalInventoryPanel(entity)); + } + + if(InventoryUtils.hasEquipInventory(entity)){ + rVal.addChild(EquipmentInventoryPanel.createEquipmentInventoryPanel(entity)); + } + + Globals.signalSystem.post(SignalType.YOGA_APPLY, rVal); + + + + return rVal; + } + +} diff --git a/src/main/java/electrosphere/renderer/ui/elements/Window.java b/src/main/java/electrosphere/renderer/ui/elements/Window.java index 6822ac57..df318d8a 100644 --- a/src/main/java/electrosphere/renderer/ui/elements/Window.java +++ b/src/main/java/electrosphere/renderer/ui/elements/Window.java @@ -70,6 +70,7 @@ public class Window implements DrawableElement, ContainerElement, NavigableEleme * @param width * @param height */ + @Deprecated public Window(OpenGLState openGLState, int positionX, int positionY, int width, int height, boolean showDecorations){ try { widgetBuffer = FramebufferUtils.generateTextureFramebuffer(openGLState, width, height); @@ -97,6 +98,40 @@ public class Window implements DrawableElement, ContainerElement, NavigableEleme this.setHeight(height); } + /** + * Private constructor + * @param openGLState + * @param positionX + * @param positionY + * @param width + * @param height + */ + private Window(OpenGLState openGLState, int positionX, int positionY, int width, int height){ + try { + widgetBuffer = FramebufferUtils.generateTextureFramebuffer(openGLState, width, height); + } catch(Exception e){ + LoggerInterface.loggerRenderer.ERROR(e); + } + customMat.setTexturePointer(widgetBuffer.getTexture().getTexturePointer()); + float ndcWidth = (float)width/Globals.WINDOW_WIDTH; + float ndcHeight = (float)height/Globals.WINDOW_HEIGHT; + float ndcX = (float)positionX/Globals.WINDOW_WIDTH; + float ndcY = (float)positionY/Globals.WINDOW_HEIGHT; + boxPosition = new Vector3f(ndcX,ndcY,0); + boxDimensions = new Vector3f(ndcWidth,ndcHeight,0); + //yoga node for the actually visible part + this.yogaNode = Yoga.YGNodeNew(); + this.layout = YGNode.create(this.yogaNode).layout(); + //yoga node for placement + this.parentWindowYogaNode = Yoga.YGNodeNew(); + Yoga.YGNodeInsertChild(this.parentWindowYogaNode, this.yogaNode, 0); + setParentAlignContent(YogaAlignment.Start); + setParentAlignItem(YogaAlignment.Start); + setParentJustifyContent(YogaJustification.Start); + this.setMinWidth(width); + this.setMinHeight(height); + } + /** * Creates a window * @param openGLState The opengl state @@ -112,6 +147,36 @@ public class Window implements DrawableElement, ContainerElement, NavigableEleme return rVal; } + /** + * Creates an expandable window + * @param openGLState The opengl state + * @param posX The x position of the window + * @param posY The y position of the window + * @param width The width of the window + * @param height The height of the window + * @return The window element + */ + public static Window createExpandable(OpenGLState openGLState, int posX, int posY, int width, int height){ + Window rVal = new Window(openGLState, posX, posY, width, height); + return rVal; + } + + /** + * Creates an expandable window + * @param openGLState The opengl state + * @param posX The x position of the window + * @param posY The y position of the window + * @param width The width of the window + * @param height The height of the window + * @return The window element + */ + public static Window createExpandableCenterAligned(OpenGLState openGLState, int width, int height){ + Window rVal = new Window(openGLState, 0, 0, width, height); + rVal.setParentAlignItem(YogaAlignment.Center); + rVal.setParentJustifyContent(YogaJustification.Center); + return rVal; + } + @Override public void draw( RenderPipelineState renderPipelineState,