diff --git a/.gitignore b/.gitignore index 2c74bff9..dbd85752 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,9 @@ /saves/random_sp_world /saves/defaultLevel* +#screenshots +/assets/Screenshots + #debug /netmonitor diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index aab801c6..2e2af399 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -417,6 +417,10 @@ Clean up framebuffer class - Comment everything - Error checking Overhaul opengl error checking generally (as in, actually use it) + - Add all over the place to help debugging graphics issues + - Handle uniforms being sent to shaders that don't have the uniform defined +Extracting pixels from framebuffers + # TODO diff --git a/src/main/java/electrosphere/controls/ControlHandler.java b/src/main/java/electrosphere/controls/ControlHandler.java index 4d6129d5..bca161b8 100644 --- a/src/main/java/electrosphere/controls/ControlHandler.java +++ b/src/main/java/electrosphere/controls/ControlHandler.java @@ -979,7 +979,9 @@ public class ControlHandler { //controls Globals.controlHandler.hintUpdateControlState(ControlsState.INVENTORY); //play sound effect - Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/openMenu.ogg", VirtualAudioSourceType.UI, false); + if(Globals.virtualAudioSourceManager != null){ + Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/openMenu.ogg", VirtualAudioSourceType.UI, false); + } // Globals.openInventoriesCount++; } else if(InventoryUtils.hasNaturalInventory(Globals.playerEntity) && Globals.elementManager.getWindow(WindowUtils.getInventoryWindowID(InventoryUtils.getNaturalInventory(Globals.playerEntity).getId())) != null){ @@ -1004,7 +1006,9 @@ public class ControlHandler { //controls Globals.controlHandler.hintUpdateControlState(ControlsState.INVENTORY); //play sound effect - Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/openMenu.ogg", VirtualAudioSourceType.UI, false); + if(Globals.virtualAudioSourceManager != null){ + Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/openMenu.ogg", VirtualAudioSourceType.UI, false); + } // Globals.openInventoriesCount++; } else if(InventoryUtils.hasEquipInventory(Globals.playerEntity) && Globals.elementManager.getWindow(WindowStrings.WINDOW_CHARACTER) != null){ diff --git a/src/main/java/electrosphere/menu/ingame/MenuGeneratorsInventory.java b/src/main/java/electrosphere/menu/ingame/MenuGeneratorsInventory.java index b58cb718..d647b096 100644 --- a/src/main/java/electrosphere/menu/ingame/MenuGeneratorsInventory.java +++ b/src/main/java/electrosphere/menu/ingame/MenuGeneratorsInventory.java @@ -53,7 +53,9 @@ public class MenuGeneratorsInventory { Globals.controlHandler.hintUpdateControlState(ControlsState.MAIN_GAME); } //play sound effect - Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/closeMenu.ogg", VirtualAudioSourceType.UI, false); + if(Globals.virtualAudioSourceManager != null){ + Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/closeMenu.ogg", VirtualAudioSourceType.UI, false); + } return false; }}); @@ -136,7 +138,9 @@ public class MenuGeneratorsInventory { container.removeChild(panel); WindowUtils.pushItemIconToItemWindow(panel); //play sound effect - Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/inventoryGrabItem.ogg", VirtualAudioSourceType.UI, false); + if(Globals.virtualAudioSourceManager != null){ + Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/inventoryGrabItem.ogg", VirtualAudioSourceType.UI, false); + } return false; }}); panel.setOnDrag(new DragEventCallback() {public boolean execute(DragEvent event){ @@ -179,7 +183,9 @@ public class MenuGeneratorsInventory { //re-render inventory WindowUtils.replaceWindow(WindowUtils.getInventoryWindowID(inventory.getId()), MenuGeneratorsInventory.createNaturalInventoryMenu(inventory)); //play sound effect - Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/inventorySlotItem.ogg", VirtualAudioSourceType.UI, false); + if(Globals.virtualAudioSourceManager != null){ + Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/inventorySlotItem.ogg", VirtualAudioSourceType.UI, false); + } } //now the fun begins :) //if transfer item @@ -225,7 +231,9 @@ public class MenuGeneratorsInventory { Globals.controlHandler.hintUpdateControlState(ControlsState.MAIN_GAME); } //play sound effect - Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/closeMenu.ogg", VirtualAudioSourceType.UI, false); + if(Globals.virtualAudioSourceManager != null){ + Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/closeMenu.ogg", VirtualAudioSourceType.UI, false); + } return false; }}); @@ -304,7 +312,9 @@ public class MenuGeneratorsInventory { container.removeChild(panel); WindowUtils.pushItemIconToItemWindow(panel); //play sound effect - Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/inventoryGrabItem.ogg", VirtualAudioSourceType.UI, false); + if(Globals.virtualAudioSourceManager != null){ + Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/inventoryGrabItem.ogg", VirtualAudioSourceType.UI, false); + } return false; }}); panel.setOnDrag(new DragEventCallback() {public boolean execute(DragEvent event){ @@ -340,7 +350,9 @@ public class MenuGeneratorsInventory { ClientEquipState equipState = ClientEquipState.getEquipState(Globals.playerEntity); equipState.commandAttemptEquip(item,inventory.getEquipPointFromSlot(slots.get(itemId))); //play sound effect - Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/inventorySlotItem.ogg", VirtualAudioSourceType.UI, false); + if(Globals.virtualAudioSourceManager != null){ + Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/inventorySlotItem.ogg", VirtualAudioSourceType.UI, false); + } } //update ui Globals.dragSourceInventory = null; diff --git a/src/main/java/electrosphere/renderer/framebuffer/Framebuffer.java b/src/main/java/electrosphere/renderer/framebuffer/Framebuffer.java index eced3f3f..33c0b405 100644 --- a/src/main/java/electrosphere/renderer/framebuffer/Framebuffer.java +++ b/src/main/java/electrosphere/renderer/framebuffer/Framebuffer.java @@ -1,18 +1,23 @@ package electrosphere.renderer.framebuffer; import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; import electrosphere.engine.Globals; import electrosphere.logger.LoggerInterface; import electrosphere.renderer.OpenGLState; import electrosphere.renderer.RenderingEngine; import electrosphere.renderer.texture.Texture; +import electrosphere.util.FileUtils; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; +import javax.imageio.ImageIO; + import org.lwjgl.opengl.GL40; import org.lwjgl.system.MemoryUtil; @@ -225,6 +230,7 @@ public class Framebuffer { public BufferedImage getPixels(OpenGLState openGLState){ BufferedImage rVal = null; bind(openGLState); + GL40.glReadBuffer(GL40.GL_COLOR_ATTACHMENT0); int offsetX = 0; int offsetY = 0; int width = openGLState.getViewport().x; @@ -242,12 +248,44 @@ public class Framebuffer { } //get pixel data try { - int bufferSize = width * height * pixelFormatToBytes(pixelFormat,type); + int bytesPerPixel = pixelFormatToBytes(pixelFormat,type); + int bufferSize = width * height * bytesPerPixel; ByteBuffer buffer = MemoryUtil.memAlloc(bufferSize); openGLState.glViewport(width, height); GL40.glReadPixels(offsetX, offsetY, width, height, pixelFormat, type, buffer); + Globals.renderingEngine.checkError(); //convert to a buffered images - + rVal = new BufferedImage(width,height,BufferedImage.TYPE_INT_ARGB); + for(int x = 0; x < width; x++){ + for(int y = 0; y < height; y++){ + int i = (x + (width * y)) * bytesPerPixel; + int red = buffer.get(i) & 0xFF; + int green = buffer.get(i + 1) & 0xFF; + int blue = buffer.get(i + 2) & 0xFF; + if(red != 0 || green != 0 || blue != 0){ + System.out.println(x + " " + y); + System.out.println(red + " " + green + " " + blue); + } + int alpha = 255; + if(pixelFormat == GL40.GL_RGBA){ + alpha = buffer.get(i + 3) & 0xFF; + } + rVal.setRGB(x, height - (y + 1), (alpha << 24) | (red << 16) | (green << 8) | blue); + } + } + //write the buffered image out + try { + File outputFile = FileUtils.getAssetFile("Screenshots/" + System.currentTimeMillis() + ".png"); + if(!outputFile.getParentFile().exists()){ + outputFile.getParentFile().mkdirs(); + } + if(!outputFile.exists()){ + outputFile.createNewFile(); + } + ImageIO.write(rVal,"png",outputFile); + } catch (IOException e) { + LoggerInterface.loggerRenderer.ERROR(e); + } //memory management MemoryUtil.memFree(buffer); } catch (OutOfMemoryError e){ @@ -271,6 +309,9 @@ public class Framebuffer { case GL40.GL_RGB: { multiplier = 3; } break; + default: { + LoggerInterface.loggerRenderer.WARNING("Trying to export framebuffer that has image of unsupported pixel format"); + } break; } int bytesPerComponent = 1; switch(type){ @@ -280,6 +321,9 @@ public class Framebuffer { case GL40.GL_UNSIGNED_BYTE: { bytesPerComponent = 1; } break; + default: { + LoggerInterface.loggerRenderer.WARNING("Trying to export framebuffer that has image of unsupported datatype"); + } break; } return multiplier * bytesPerComponent; }