diff --git a/resources/icon-sprites.png b/resources/icon-sprites.png new file mode 100644 index 0000000..b1a9522 Binary files /dev/null and b/resources/icon-sprites.png differ diff --git a/resources/icon.png b/resources/icon.png deleted file mode 100644 index 88a9d5e..0000000 Binary files a/resources/icon.png and /dev/null differ diff --git a/src/com/sheepit/client/Gui.java b/src/com/sheepit/client/Gui.java index 2e4882f..c82ae9b 100644 --- a/src/com/sheepit/client/Gui.java +++ b/src/com/sheepit/client/Gui.java @@ -25,7 +25,9 @@ public interface Gui { public void stop(); public void status(String msg_); - + + public void updateTrayIcon(Integer percentage_); + public void setRenderingProjectName(String name_); public void setRemainingTime(String time_); diff --git a/src/com/sheepit/client/Job.java b/src/com/sheepit/client/Job.java index 9f6cd6b..cfdb2a6 100644 --- a/src/com/sheepit/client/Job.java +++ b/src/com/sheepit/client/Job.java @@ -40,6 +40,8 @@ import java.util.Observer; import java.util.TimeZone; import java.util.Timer; import java.util.TimerTask; +import java.util.regex.Pattern; +import java.util.regex.Matcher; import com.sheepit.client.Configuration.ComputeType; import com.sheepit.client.Error.Type; @@ -54,7 +56,9 @@ public class Job { public static final String UPDATE_METHOD_BY_REMAINING_TIME = "remainingtime"; public static final String UPDATE_METHOD_BLENDER_INTERNAL_BY_PART = "blenderinternal"; public static final String UPDATE_METHOD_BY_TILE = "by_tile"; - + + public static final int SHOW_BASE_ICON = -1; + private String frameNumber; private String sceneMD5; private String rendererMD5; @@ -271,9 +275,18 @@ public class Job { log.debug("renderer output"); try { + int progress = -1; + + Pattern tilePattern = Pattern.compile(" ([0-9]+)\\s?\\/\\s?([0-9]+) "); + + // Initialise the progress bar in the icon (0% completed at this time) + gui.updateTrayIcon(0); + while ((line = input.readLine()) != null) { log.debug(line); - + + progress = computeRenderingProgress(line, tilePattern, progress); + updateRenderingMemoryPeak(line); if (configuration.getMaxMemory() != -1 && process.getMemoryUsed() > configuration.getMaxMemory()) { log.debug("Blocking render because process ram used (" + process.getMemoryUsed() + "k) is over user setting (" + configuration.getMaxMemory() + "k)"); @@ -282,6 +295,11 @@ public class Job { if (script_file != null) { script_file.delete(); } + + // Once the process is finished (either finished successfully or with an error) move back to + // base icon (isolated S with no progress bar) + gui.updateTrayIcon(Job.SHOW_BASE_ICON); + return Error.Type.RENDERER_OUT_OF_MEMORY; } @@ -291,6 +309,10 @@ public class Job { if (script_file != null) { script_file.delete(); } + + // Put back base icon + gui.updateTrayIcon(Job.SHOW_BASE_ICON); + return error; } @@ -304,6 +326,10 @@ public class Job { // most likely The handle is invalid log.error("Job::render exception(B) (silent error) " + err1); } + + // Put back base icon + gui.updateTrayIcon(Job.SHOW_BASE_ICON); + log.debug("end of rendering"); } catch (Exception err) { @@ -397,7 +423,26 @@ public class Job { return Error.Type.OK; } - + + private int computeRenderingProgress(String line, Pattern tilePattern, int currentProgress) { + Matcher standardTileInfo = tilePattern.matcher(line); + int newProgress = currentProgress; + + if (standardTileInfo.find()) { + int tileJustProcessed = Integer.parseInt(standardTileInfo.group(1)); + int totalTilesInJob = Integer.parseInt(standardTileInfo.group(2)); + + newProgress = Math.abs((tileJustProcessed * 100) / totalTilesInJob); + } + + // Only update the tray icon if percentage has changed + if (newProgress != currentProgress) { + gui.updateTrayIcon(newProgress); + } + + return newProgress; + } + private void updateRenderingStatus(String line) { if (getUpdateRenderingStatusMethod() != null && getUpdateRenderingStatusMethod().equals(Job.UPDATE_METHOD_BLENDER_INTERNAL_BY_PART)) { String search = " Part "; diff --git a/src/com/sheepit/client/standalone/GuiSwing.java b/src/com/sheepit/client/standalone/GuiSwing.java index 3d518fe..355185f 100644 --- a/src/com/sheepit/client/standalone/GuiSwing.java +++ b/src/com/sheepit/client/standalone/GuiSwing.java @@ -31,16 +31,21 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowEvent; import java.awt.event.WindowStateListener; +import java.awt.image.BufferedImage; import java.net.URL; +import java.nio.Buffer; import java.util.Timer; import java.util.TimerTask; +import java.io.IOException; + import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.border.EmptyBorder; +import javax.imageio.ImageIO; import com.sheepit.client.Client; import com.sheepit.client.Configuration; @@ -72,6 +77,9 @@ public class GuiSwing extends JFrame implements Gui { private boolean waitingForAuthentication; private Client client; + private BufferedImage iconSprites; + private BufferedImage[] trayIconSprites; + @Getter @Setter private SettingsLoader settingsLoader; @@ -120,13 +128,21 @@ public class GuiSwing extends JFrame implements Gui { sysTray = null; } } - - URL iconUrl = getClass().getResource("/icon.png"); - if (iconUrl != null) { - ImageIcon img = new ImageIcon(iconUrl); - setIconImage(img.getImage()); + + // load the images sprite and split into individual images + URL spriteSequenceUrl = getClass().getResource("/icon-sprites.png"); + + if (spriteSequenceUrl != null) { + try { + iconSprites = ImageIO.read(spriteSequenceUrl); + trayIconSprites = new BufferedImage[101 * 1]; // sprite sheet has 101 images in 1 column + + setIconImage(extractImageFromSprite(-1)); // sprite 0 is standard Sheep It! icon + } catch (IOException e) { + e.printStackTrace(); + } } - + setTitle(title); setSize(520, 760); @@ -303,9 +319,9 @@ public class GuiSwing extends JFrame implements Gui { public TrayIcon getTrayIcon() { final PopupMenu trayMenu = new PopupMenu(); - - URL iconUrl = getClass().getResource("/icon.png"); - Image img = Toolkit.getDefaultToolkit().getImage(iconUrl); + + // on start, show the base icon + Image img = extractImageFromSprite(-1); final TrayIcon icon = new TrayIcon(img); MenuItem exit = new MenuItem("Exit"); @@ -350,7 +366,36 @@ public class GuiSwing extends JFrame implements Gui { return icon; } - + + private Image extractImageFromSprite(int spriteNumber) { + // Sprite structure + // Image 0: base sprite + // Images 1-101: progress bar percentage from 0 to 100 + // + // Always add +1 to the icon requested. + // -1 turns into 0 (base sprite with no progress bar) + // 0 to 101 turns into 1 to 101 (progress sequence starts in sprite 1 and ends on sprite 101) + ImageIcon img = new ImageIcon(iconSprites.getSubimage(0, (spriteNumber + 1) * 114, 114, 114)); + + return img.getImage(); + } + + @Override + public void updateTrayIcon(Integer percentage) { + // update the app icon on the app bar + Image img = extractImageFromSprite(percentage); + setIconImage(img); + + // if the app supports the system tray, update as well + if (sysTray != null && SystemTray.isSupported()) { + if (trayIcon != null) { + trayIcon.setImage(img); + trayIcon.setImageAutoSize(true); // use this method to ensure that icon is refreshed when on + // the tray + } + } + } + public class ThreadClient extends Thread { @Override public void run() { diff --git a/src/com/sheepit/client/standalone/GuiText.java b/src/com/sheepit/client/standalone/GuiText.java index 814559e..00896c7 100644 --- a/src/com/sheepit/client/standalone/GuiText.java +++ b/src/com/sheepit/client/standalone/GuiText.java @@ -88,7 +88,11 @@ public class GuiText implements Gui { public void stop() { Runtime.getRuntime().halt(0); } - + + @Override + public void updateTrayIcon(Integer percentage) { + } + @Override public void status(String msg_) { System.out.println(msg_); diff --git a/src/com/sheepit/client/standalone/GuiTextOneLine.java b/src/com/sheepit/client/standalone/GuiTextOneLine.java index 04cddd1..4ac551f 100644 --- a/src/com/sheepit/client/standalone/GuiTextOneLine.java +++ b/src/com/sheepit/client/standalone/GuiTextOneLine.java @@ -94,7 +94,11 @@ public class GuiTextOneLine implements Gui { public void stop() { Runtime.getRuntime().halt(0); } - + + @Override + public void updateTrayIcon(Integer percentage) { + } + @Override public void status(String msg_) { status = msg_;